goals-onboarding
Skill0 starsChanged 4 months agoApache-2.0View on GitHub
Interviews the user for risk tolerance, goals, time horizon, and constraints; ingests holdings, liabilities, and checking spending history; produces an Investment Policy Statement (IPS) written to long-term memory. Use when onboarding a new user with no active IPS, when the user reports a life event affecting their goals, or when Portfolio Analysis recommends a drift-triggered policy review.
In this repository8 other files it gives its agents.
- AGENTS.mdAGENTS.md
- action-draftingSkill
- equity-researchSkill
- portfolio-analysisSkill
- researchSkill
- reviewerSkill
- spending-analysisSkill
- suitabilitySkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 86
Risk tolerance: Not asked directly ("are you conservative or aggressive?") — derived deterministically from two questions, so the mapping …
- Very specific: line 159
If the user abandons the interview before all required IPS fields are answered, the Managed Agent does not emit a complete result and no …
- Very specific: line 197
Default target_allocation bands match the risk-tier table and are overridable before the write occurs
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
goals-onboarding
Purpose
Interviews the user for risk tolerance, goals, time horizon, and
constraints; ingests current holdings, current liabilities, and checking
spending history; produces an
InvestmentPolicyStatement — the
reference plan every other skill and the Reviewer/Critic reads against —
and captures a LiabilitiesSnapshot,
since debt data isn't derivable from checking transactions alone.
This is the only skill in this project with no path to financial execution. It reads context and writes policy; it never drafts or executes a trade. Keep it that way — don't add tool scopes here that belong to Action Drafting.
When this skill runs
| Trigger | Meaning | Result |
initial | No active IPS exists for this user | Creates version 1 |
life_event | User reports a change (new goal, changed timeline, etc.) mid-conversation | Creates version N+1 |
drift_review | Portfolio Analysis reports drift the current IPS bands don't account for, and recommends revisiting | Creates version N+1, pre-filled with prior answers for the user to confirm or change |
The decision to invoke this skill (e.g. noticing a life-event mention) is the root planner's, not this skill's own — this skill only defines what it does once invoked, per ADR-0004.
Inputs
| Field | Source | Required |
user_id | Orchestrator | Yes |
trigger | Orchestrator (initial | life_event | drift_review) | Yes |
existing_ips_ref | Firestore — active IPS for this user, if any | Required when trigger != initial |
HoldingsSnapshot | Firestore, read-only | Yes — informs feasibility discussion (e.g. a goal the current portfolio can't plausibly reach) |
Existing LiabilitiesSnapshot, if any | Firestore, read-only | Required when trigger != initial — presented back to the user to confirm/update rather than re-asked from scratch |
| Checking transaction history | BigQuery, read-only, aggregated | Yes — informs liquidity needs (spending patterns, existing reserve) |
W2Document, if any | Firestore, read-only | Optional — informs income verification and retirement deferral capacity (Box 12 401(k)) |
| Interview responses | User, gathered interactively during the skill's own multi-turn conversation | Yes |
The interview itself is multi-turn and not turn-by-turn specified here — that's an implementation detail. What's specified is the mapping from interview content to IPS fields, below.
Interview → IPS field mapping
Goals. Free-form goal name, target amount, target date — one or more.
Each becomes a goals[] entry. Reality-check against current holdings +
savings rate (derived from checking transaction data); if a goal's target is
implausible given the timeline, flag it to the user during the interview
— don't silently accept or silently block.
Liabilities. Asked directly, one entry per debt: type (credit card,
mortgage, auto loan, student loan, HELOC, other), balance, interest
rate, minimum payment. If an existing LiabilitiesSnapshot was passed in
(revision triggers), present it back for the user to confirm or update
rather than re-asking from scratch. Written as a
LiabilitiesSnapshot —
separately from the IPS, since it's current-state data that changes on
its own schedule (a credit card balance moves monthly; policy doesn't).
Not yet in scope: this data isn't automatically factored into the
risk_tolerance mapping below. High-interest debt arguably should
temper an otherwise-aggressive allocation (risk capacity vs. risk
tolerance) — the field exists so a future Reviewer rule or an explicit
prompt to the user ("you're carrying 22% APR debt — still want an
aggressive allocation?") can use it. Wiring that logic in is a
deliberate next decision, not an oversight to silently paper over here.
Risk tolerance. Not asked directly ("are you conservative or aggressive?") — derived deterministically from two questions, so the mapping is testable rather than a judgment call buried in a prompt:
- Time horizon in years (for the primary goal)
- Reaction to a hypothetical 20% portfolio drawdown:
sell/hold/buy_more
| time_horizon_years | drawdown_reaction | → risk_tolerance |
| ≥ 15 | hold or buy_more | aggressive |
| ≥ 7 | hold or buy_more | moderate |
| any | sell | conservative |
| < 7 | hold or buy_more | moderate |
Time horizon. Directly from the primary goal's target date.
Liquidity needs. reserve_months asked directly; known_upcoming_expenses_usd
summed from user-reported near-term expenses.
Target allocation. Propose default bands per risk tier (below) as a starting point; user can override any band before confirming. Never finalize without an explicit confirmation step — this is the one place in the skill where the interactive interview itself functions as the approval gate, since there's no separate Reviewer/HITL step for policy changes (only for trades).
| risk_tolerance | Default target (min–max band) |
conservative | equity 30% (20–40), bonds 60% (50–70), cash 10% (5–15) |
moderate | equity 60% (50–70), bonds 30% (20–40), cash 10% (5–15) |
aggressive | equity 85% (75–95), bonds 10% (0–20), cash 5% (0–10) |
Constraints. excluded_tickers/excluded_sectors asked directly
(optional, default empty). concentration_limit_percent defaults to 15,
user-overridable. account_type and tax_loss_harvesting_enabled asked
directly.
Approval thresholds. approval_required_above_usd and
approval_required_above_percent — asked directly, with a suggested
default (e.g. $1,000 or 5% of portfolio, whichever is lower) the user can
adjust.
Output
Produces a typed GoalsOnboardingResult
carrying the synthesized interview responses. The trusted orchestrator
validates this structured output and executes the corresponding Firestore
writes:
- One
InvestmentPolicyStatementinstance, written to Firestore, plus - One
LiabilitiesSnapshot, written or overwritten in Firestore (current-state, not versioned — unlike the IPS below, there's no history to preserve here, the latest snapshot simply replaces the prior one).
Versioning invariant (IPS only): exactly one document with
status: "active" per ips_id at any time.
trigger: initial→ write version 1,status: "active".trigger: life_eventordrift_review→ write version N+1 withstatus: "active", and update the previous active version's document:status → "superseded",superseded_by → "{ips_id}:v{N+1}". These two writes happen together — never leave two active versions, or zero.
A summarized version (risk tolerance, goals, key constraints — not the full document) is also pushed by the orchestrator to Agent Platform Memory Bank for semantic recall in future sessions.
Failure mode: incomplete interview
If the user abandons the interview before all required IPS fields are
answered, the Managed Agent does not emit a complete result and no
documents are written — neither the IPS nor the LiabilitiesSnapshot.
Partial state is never persisted: a half-complete IPS would fail schema
validation, and a document that doesn't validate should never exist in
Firestore. Resume from where the user left off on the next invocation rather
than starting over, if practical.
Tools / permissions required
- Managed Agent sandbox: conversational interaction with the user (
RequestInput) - Orchestrator (outside sandbox):
- Firestore: read
holdings, readliabilities, readw2_documents, read/writeips, writeliabilities, writeaudit_log - BigQuery: read
checking_transactions(aggregate queries only) - Agent Platform Memory Bank: write (summarized preferences)
- Firestore: read
- No trade-execution tools, no Alpaca access, no write access inside the sandbox.
Registry metadata
- Registered as:
projects/{project}/locations/{location}/skills/private-goals-onboarding(self-registered skills are namespaced under theprivate-publisher prefix — see ADR-0006) - Skill revision: 0.2.0 (draft — not yet registered)
- Approval scope:
read:holdings,read:liabilities,read:spending,read:ips,read:w2
Acceptance criteria
trigger: initial, no existing IPS → produces exactly one IPS document, version 1,status: active, valid againstips.schema.json, plus oneLiabilitiesSnapshotvalid againstliabilities.schema.jsontrigger: life_eventordrift_reviewwith an existing active IPS → produces version N+1active; previous version flips tosupersededwithsuperseded_byset; exactly one active version exists afterward;LiabilitiesSnapshotis overwritten, not versioned- Interview abandoned mid-way → zero documents written (neither IPS nor
LiabilitiesSnapshot) risk_toleranceis set via the mapping table above for every tested(time_horizon_years, drawdown_reaction)combination — not free-form- Default
target_allocationbands match the risk-tier table and are overridable before the write occurs - On a revision trigger, an existing
LiabilitiesSnapshotis presented back to the user rather than re-collected from scratch - Emits
AuditLogEntryrecords:skill_invokedat start,ips_created(initial) orips_superseded(revision) on write — seeaudit-log-entry.schema.json
Non-goals
The risk-tolerance mapping above is a simplified deterministic heuristic
for demo purposes — it is not a licensed suitability assessment and
shouldn't be presented as one. See project-level non-goals in
00-overview.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

