feat(context): founder-context + per-squad alignment as first-class layers#770
feat(context): founder-context + per-squad alignment as first-class layers#770kokevidaurre wants to merge 4 commits intodevelopfrom
Conversation
…ayers
Adds two new layers to gatherSquadContext() so agents run aligned with
the founder's live strategic state, not just squad-internal goals:
- L9: .agents/memory/company/founder-context.md (universal)
Live business state, active client work, priority pipeline,
in-flight threads, recent decisions, dismissed topics, hands-off PRs.
- L10: .agents/memory/{squad}/founder-alignment.md (per-squad)
Domain-specific translation: how THIS squad contributes to the
founder's current priorities this cycle, with named files/PRs/clients.
Both layers inject at the TOP of the action-first ordering so LLMs
give them maximum attention. Visible to all 5 roles.
Adds a pre-step to `squads run --org` that runs
`scripts/founder-context-digest.py` (in project root) when context is
stale (>2h) or missing. Hard-blocks the org cycle on digest failure
rather than running unaligned agents.
Token budgets bumped: scanner 4k→6k, worker/verifier 12k→16k,
lead 24k→32k, coo 32k→40k.
Closes #769
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…ontext-digest.py Preferred path is .claude/hooks/ (version-controlled, fits hq convention). Falls back to scripts/ for projects organized differently.
There was a problem hiding this comment.
Code Review
This pull request introduces a founder context system designed to align agent squads with live strategic goals by generating and injecting universal and squad-specific alignment files into agent prompts. Key changes include the implementation of a context refresh mechanism using a Python digest script, updated token budgets, and the prioritization of these new context layers in the prompt assembly. Feedback focuses on ensuring the --force flag is correctly propagated, improving the robustness and cross-platform compatibility of the script execution, extending the refresh logic to single-squad runs, and maintaining consistency in documentation comments.
| // into per-squad alignment files so agents run aligned with the founder's | ||
| // current pipeline, not generic squad goals. | ||
| if (!options.dryRun) { | ||
| const ctxResult = refreshFounderContext(); |
There was a problem hiding this comment.
The refreshFounderContext call should pass the force option from the CLI to ensure that the --force flag correctly triggers a context refresh even if the files are not yet stale.
| const ctxResult = refreshFounderContext(); | |
| const ctxResult = refreshFounderContext({ force: options.force }); |
| } | ||
|
|
||
| if (!isStale) return 'fresh'; | ||
|
|
||
| writeLine(` ${colors.dim}founder-context: refreshing from CC sessions + git activity...${RESET}`); |
There was a problem hiding this comment.
Hardcoding python3 may cause issues on systems where the executable is named python (e.g., Windows). Additionally, it's safer to check result.error to handle cases where the command fails to start or times out, rather than just checking result.status.
| } | |
| if (!isStale) return 'fresh'; | |
| writeLine(` ${colors.dim}founder-context: refreshing from CC sessions + git activity...${RESET}`); | |
| const pythonCmd = process.platform === "win32" ? "python" : "python3"; | |
| const result = spawnSync(pythonCmd, [digestScript], { | |
| cwd: projectRoot, | |
| stdio: "inherit", | |
| timeout: 12 * 60 * 1000, | |
| }); | |
| if (result.error) { | |
| const isTimeout = (result.error as any).code === "ETIMEDOUT"; | |
| writeLine( | |
| " " + colors.yellow + "founder-context: digest " + (isTimeout ? "timed out" : "failed to start") + ": " + result.error.message + RESET + "\n" | |
| ); | |
| return "failed"; | |
| } |
| // Step 0: REFRESH founder context — distill recent sessions + git activity | ||
| // into per-squad alignment files so agents run aligned with the founder's | ||
| // current pipeline, not generic squad goals. | ||
| if (!options.dryRun) { | ||
| const ctxResult = refreshFounderContext(); | ||
| if (ctxResult === 'failed') { | ||
| writeLine(` ${colors.red}Aborting org cycle. Fix the digest script and retry.${RESET}\n`); | ||
| return; | ||
| } | ||
| } |
There was a problem hiding this comment.
The founder context refresh is currently only wired into the --org cycle. However, the PR motivation mentions that single squad runs (e.g., squads run intelligence) also benefit from this alignment. If a user runs a single squad and the context is missing or stale, they won't get the 'live' strategic state. Consider moving this refresh step so it applies to single squad runs as well, perhaps with a shorter timeout or only if the files are missing.
| scanner: 6000, // ~1500 tokens — company + priorities + goals + agent + state + founder ctx | ||
| worker: 16000, // ~4000 tokens — + feedback + founder ctx + alignment | ||
| lead: 32000, // ~8000 tokens — all layers + founder ctx + alignment | ||
| coo: 40000, // ~10000 tokens — all layers + expanded + founder ctx | ||
| verifier: 16000, // similar needs to worker |
There was a problem hiding this comment.
The comments for ROLE_BUDGETS are inconsistent regarding the new layers. For example, the scanner role comment mentions 'founder ctx' but the code also grants it 'alignment' (layer 10). The coo role comment omits the new layers entirely.
| scanner: 6000, // ~1500 tokens — company + priorities + goals + agent + state + founder ctx | |
| worker: 16000, // ~4000 tokens — + feedback + founder ctx + alignment | |
| lead: 32000, // ~8000 tokens — all layers + founder ctx + alignment | |
| coo: 40000, // ~10000 tokens — all layers + expanded + founder ctx | |
| verifier: 16000, // similar needs to worker | |
| scanner: 6000, // ~1500 tokens — company + priorities + goals + agent + state + founder ctx + alignment | |
| worker: 16000, // ~4000 tokens — + feedback + founder ctx + alignment | |
| lead: 32000, // ~8000 tokens — all layers + founder ctx + alignment | |
| coo: 40000, // ~10000 tokens — all layers + expanded + founder ctx + alignment | |
| verifier: 16000, // similar needs to worker |
| scanner: new Set([1, 2, 3, 4, 5, 9, 10]), // identity + focus + role + memory + founder ctx | ||
| worker: new Set([1, 2, 3, 4, 5, 6, 9, 10]), // + feedback + founder ctx | ||
| lead: new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), // all layers + founder ctx | ||
| coo: new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), // all layers + founder ctx + expanded budget | ||
| verifier: new Set([1, 2, 3, 4, 5, 6, 9, 10]), // same as worker + founder ctx |
There was a problem hiding this comment.
The comments for ROLE_SECTIONS should be updated to reflect that all roles now receive both layer 9 (founder-context) and layer 10 (founder-alignment).
| scanner: new Set([1, 2, 3, 4, 5, 9, 10]), // identity + focus + role + memory + founder ctx | |
| worker: new Set([1, 2, 3, 4, 5, 6, 9, 10]), // + feedback + founder ctx | |
| lead: new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), // all layers + founder ctx | |
| coo: new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), // all layers + founder ctx + expanded budget | |
| verifier: new Set([1, 2, 3, 4, 5, 6, 9, 10]), // same as worker + founder ctx | |
| scanner: new Set([1, 2, 3, 4, 5, 9, 10]), // identity + focus + role + memory + founder ctx + alignment | |
| worker: new Set([1, 2, 3, 4, 5, 6, 9, 10]), // + feedback + founder ctx + alignment | |
| lead: new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), // all layers + founder ctx + alignment | |
| coo: new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), // all layers + founder ctx + alignment + expanded budget | |
| verifier: new Set([1, 2, 3, 4, 5, 6, 9, 10]), // same as worker + founder ctx + alignment |
Reverting the L11 (drive-map) layer from gatherSquadContext. L9 (founder-context.md) and L10 (founder-alignment.md) are generic patterns that any squads-cli user can adopt — every business has live strategic context and per-squad contributions to current priorities. These slots stay in the public CLI. L11 was hq-specific (drive-map.md + drive-erp.md naming, our particular Hub sheet / GPS DuckDB architecture). That belongs inline in our hq content, not as a slot in the public loader. Approach: the digest script (hq/.claude/hooks/founder-context-digest.py) embeds drive-map + drive-erp content directly into founder-context.md when generating. Squad agents see the structural reference via L9, not via a separate slot. CLI stays generic; embedding is the user's choice. Effective context for our agents is unchanged (~39.7K chars for lead role).
…ructural ref Two related fixes for context loading in gatherSquadContext: 1. Off-by-4 bug in addLayer: when a layer's content exceeded the remaining budget, the truncation suffix '\n...' (4 chars) pushed text.length beyond budget by exactly 4, triggering the "exhausted" path which DROPPED the entire layer rather than keeping the truncated version. Now reserves space for the suffix so truncation lands exactly within cap. 2. Bump role budgets to fit founder-context.md when it embeds Drive structural reference (drive-map + drive-erp ≈ 30K chars): scanner: 12000 → 50000 (~12500 tokens) worker: 36000 → 60000 (~15000 tokens) lead: 60000 → 80000 (~20000 tokens) coo: 72000 → 100000 (~25000 tokens) verifier: 36000 → 60000 Without these bumps, scanner/worker/verifier dropped L9 entirely because the embedded Drive map + ERP architecture pushed founder-context.md to 42K, exceeding their old budgets. Symptom: the deliverable medium decision matrix wasn't reaching workers, so they defaulted to md-only output instead of producing Doc + Calendar + Sheet artifacts. Verified: all 5 roles now see "Mandatory companion artifacts" matrix and "External communication" approval gate. Tested with customer squad (founder-context.md ≈ 42K, total context 50K-64K depending on role).
Closes #769.
Summary
Adds two new context layers to
gatherSquadContext()so squads run aligned with the founder's live strategic state, not just squad-internal goals.company/founder-context.md— universal: live business state, active clients, priority pipeline, in-flight threads, decisions, dismissed topics, hands-off PRs/files, recent corrections{squad}/founder-alignment.md— per-squad: "how YOUR squad contributes this cycle" with named files/PRs/clientsBoth layers inject at the top of the action-first ordering. Visible to all 5 roles (scanner, worker, lead, coo, verifier) — strategic state is always relevant.
Also adds a pre-step to
squads run --org: runsscripts/founder-context-digest.py(in project root) when context is stale (>2h) or missing. Hard-blocks the org cycle on digest failure to prevent agents running with stale or no alignment.Why this matters
Today's smoke test of
squads run intelligenceproved the gap: the agent saw a reference to founder-context.md indaily-briefing.mdbut never read the file, then merged a PR (#49 in intelligence) the founder was actively reviewing. Inlining the content as a first-class layer ensures it's loaded by the existing context system every time.Reframing: squads need affirmative alignment ("here's how to contribute from your domain"), not defensive guardrails ("don't break things"). With this layer, each squad shows up with specific named work, not generic invented tasks.
What changed
src/lib/run-context.tssrc/lib/org-cycle.tsrefreshFounderContext()helpersrc/commands/run.tsToken budgets bumped: scanner 4k→6k, worker/verifier 12k→16k, lead 24k→32k, coo 32k→40k.
Test plan
npm run build— passesnpm run typecheck— passesnpm test— 1775/1775 passgatherSquadContext('intelligence', 'intel-lead', { role: 'lead' })returns context containing both new sections +#49hands-off refrefreshFounderContext()returns 'fresh' when file is <2h old, runs digest when force/stalesquads run --org --dry-runto confirm pre-step skipped in dry-run modeBackwards compatibility
Missing files are skipped gracefully. Fresh
squads initusers see no behavior change (they have no founder-context.md or founder-alignment.md until they generate one).