initial public release
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
// Package profile parses the user's ~/.apex/config/profile.yml and renders
|
||||
// it as a compact markdown summary for splicing into the eval prompt.
|
||||
package profile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Profile struct {
|
||||
// Candidate.Email is intentionally not parsed: email is PII we do not want
|
||||
// transmitted to the eval LLM API. Same reasoning applies to phone.
|
||||
Candidate struct {
|
||||
FullName string `yaml:"full_name"`
|
||||
Location string `yaml:"location"`
|
||||
Clearance string `yaml:"clearance"`
|
||||
} `yaml:"candidate"`
|
||||
|
||||
TargetRoles struct {
|
||||
Primary []string `yaml:"primary"`
|
||||
Archetypes []struct {
|
||||
Name string `yaml:"name"`
|
||||
Level string `yaml:"level"`
|
||||
Fit string `yaml:"fit"`
|
||||
} `yaml:"archetypes"`
|
||||
} `yaml:"target_roles"`
|
||||
|
||||
// ProofPoints.URL is parsed but never rendered into the LLM prompt — proof
|
||||
// point URLs can carry tokens or session IDs. Do NOT add URL rendering
|
||||
// without first sanitizing or whitelisting domains.
|
||||
Narrative struct {
|
||||
Headline string `yaml:"headline"`
|
||||
Superpowers []string `yaml:"superpowers"`
|
||||
ProofPoints []struct {
|
||||
Name string `yaml:"name"`
|
||||
URL string `yaml:"url"`
|
||||
HeroMetric string `yaml:"hero_metric"`
|
||||
} `yaml:"proof_points"`
|
||||
} `yaml:"narrative"`
|
||||
|
||||
Compensation struct {
|
||||
TargetRange string `yaml:"target_range"`
|
||||
Currency string `yaml:"currency"`
|
||||
Minimum string `yaml:"minimum"`
|
||||
Note string `yaml:"note"`
|
||||
} `yaml:"compensation"`
|
||||
|
||||
Location struct {
|
||||
Country string `yaml:"country"`
|
||||
State string `yaml:"state"`
|
||||
Timezone string `yaml:"timezone"`
|
||||
VisaStatus string `yaml:"visa_status"`
|
||||
Remote struct {
|
||||
Preference string `yaml:"preference"`
|
||||
Exceptions string `yaml:"exceptions"`
|
||||
NotAcceptable string `yaml:"not_acceptable_for"`
|
||||
} `yaml:"remote"`
|
||||
} `yaml:"location"`
|
||||
|
||||
DealBreakers []string `yaml:"deal_breakers"`
|
||||
Priorities []string `yaml:"priorities"`
|
||||
DreamCompanies []string `yaml:"dream_companies"`
|
||||
}
|
||||
|
||||
func Load(path string) (*Profile, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var p Profile
|
||||
if err := yaml.Unmarshal(data, &p); err != nil {
|
||||
return nil, fmt.Errorf("parse profile yaml: %w", err)
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (p *Profile) Render() string {
|
||||
if p == nil {
|
||||
return ""
|
||||
}
|
||||
var b strings.Builder
|
||||
if p.Candidate.FullName != "" {
|
||||
fmt.Fprintf(&b, "- **Name:** %s\n", p.Candidate.FullName)
|
||||
}
|
||||
if p.Candidate.Location != "" {
|
||||
fmt.Fprintf(&b, "- **Location:** %s\n", p.Candidate.Location)
|
||||
}
|
||||
if p.Candidate.Clearance != "" {
|
||||
fmt.Fprintf(&b, "- **Clearance:** %s\n", p.Candidate.Clearance)
|
||||
}
|
||||
if p.Compensation.TargetRange != "" || p.Compensation.Minimum != "" {
|
||||
b.WriteString("\n**Compensation:**\n")
|
||||
if p.Compensation.TargetRange != "" {
|
||||
fmt.Fprintf(&b, "- Target range: %s\n", p.Compensation.TargetRange)
|
||||
}
|
||||
if p.Compensation.Minimum != "" {
|
||||
fmt.Fprintf(&b, "- **Hard floor:** %s (score < 2.0/5 if base falls below this)\n", p.Compensation.Minimum)
|
||||
}
|
||||
if p.Compensation.Note != "" {
|
||||
fmt.Fprintf(&b, "- Note: %s\n", p.Compensation.Note)
|
||||
}
|
||||
}
|
||||
if p.Location.Remote.Preference != "" || p.Location.VisaStatus != "" {
|
||||
b.WriteString("\n**Location & Work Style:**\n")
|
||||
if p.Location.Remote.Preference != "" {
|
||||
fmt.Fprintf(&b, "- Remote: %s\n", p.Location.Remote.Preference)
|
||||
}
|
||||
if p.Location.Remote.Exceptions != "" {
|
||||
fmt.Fprintf(&b, "- Remote exceptions: %s\n", p.Location.Remote.Exceptions)
|
||||
}
|
||||
if p.Location.VisaStatus != "" {
|
||||
fmt.Fprintf(&b, "- Visa: %s\n", p.Location.VisaStatus)
|
||||
}
|
||||
if p.Location.Timezone != "" {
|
||||
fmt.Fprintf(&b, "- Timezone: %s\n", p.Location.Timezone)
|
||||
}
|
||||
}
|
||||
if len(p.TargetRoles.Archetypes) > 0 {
|
||||
b.WriteString("\n**Target Archetypes** (must match one for score >= 4.0):\n")
|
||||
for _, a := range p.TargetRoles.Archetypes {
|
||||
if a.Name == "" {
|
||||
continue
|
||||
}
|
||||
lvl := a.Level
|
||||
if lvl == "" {
|
||||
lvl = "-"
|
||||
}
|
||||
fmt.Fprintf(&b, "- %s (%s)\n", a.Name, lvl)
|
||||
}
|
||||
} else if len(p.TargetRoles.Primary) > 0 {
|
||||
b.WriteString("\n**Target Roles:**\n")
|
||||
for _, r := range p.TargetRoles.Primary {
|
||||
if r != "" {
|
||||
fmt.Fprintf(&b, "- %s\n", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(p.DealBreakers) > 0 {
|
||||
b.WriteString("\n**Deal-Breakers** (any match -> score <= 2.0/5):\n")
|
||||
for _, d := range p.DealBreakers {
|
||||
if d != "" {
|
||||
fmt.Fprintf(&b, "- %s\n", d)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(p.DreamCompanies) > 0 {
|
||||
b.WriteString("\n**Dream Companies** (+0.5 score bonus if match):\n")
|
||||
for _, c := range p.DreamCompanies {
|
||||
if c != "" {
|
||||
fmt.Fprintf(&b, "- %s\n", c)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(p.Priorities) > 0 {
|
||||
b.WriteString("\n**Priorities (descending):**\n")
|
||||
for _, pr := range p.Priorities {
|
||||
if pr != "" {
|
||||
fmt.Fprintf(&b, "- %s\n", pr)
|
||||
}
|
||||
}
|
||||
}
|
||||
if p.Narrative.Headline != "" {
|
||||
b.WriteString("\n**Narrative:**\n")
|
||||
fmt.Fprintf(&b, "- Headline: %s\n", p.Narrative.Headline)
|
||||
}
|
||||
if len(p.Narrative.Superpowers) > 0 {
|
||||
b.WriteString("- Superpowers:\n")
|
||||
for _, s := range p.Narrative.Superpowers {
|
||||
if s != "" {
|
||||
fmt.Fprintf(&b, " - %s\n", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(p.Narrative.ProofPoints) > 0 {
|
||||
b.WriteString("- Proof points:\n")
|
||||
for _, pp := range p.Narrative.ProofPoints {
|
||||
if pp.Name == "" {
|
||||
continue
|
||||
}
|
||||
line := " - " + pp.Name
|
||||
if pp.HeroMetric != "" {
|
||||
line += " - " + pp.HeroMetric
|
||||
}
|
||||
b.WriteString(line + "\n")
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
Reference in New Issue
Block a user