diff --git a/.devflow/features/ambient-orchestrator/KNOWLEDGE.md b/.devflow/features/ambient-orchestrator/KNOWLEDGE.md index 9d325c1a..e9465b8e 100644 --- a/.devflow/features/ambient-orchestrator/KNOWLEDGE.md +++ b/.devflow/features/ambient-orchestrator/KNOWLEDGE.md @@ -5,7 +5,7 @@ description: "Use when modifying the ambient mode hooks (preamble, session-start category: architecture directories: [src/assets/scripts/hooks, src/cli/commands/ambient.ts, src/core/plugins.ts] created: 2026-07-04 -updated: 2026-07-15 +updated: 2026-08-25 --- # Ambient Orchestrator Mode @@ -37,7 +37,7 @@ The orchestrator reminder block carries an inline cross-reference comment markin ### orchestrator-charter.md -A static markdown file at `src/assets/scripts/hooks/assets/orchestrator-charter.md` consumed at runtime by `session-start-orchestrator`. Contains the full orchestrator contract: model-tier routing table (haiku/sonnet/opus), judgment-work carve-outs, delegation rules, the plan-handoff fallback bullet, and a feature-knowledge operating rule. The never-mainline rule explicitly names codebase orientation as delegated work (alongside file edits, builds, multi-file reads, and debug loops). The sonnet tier routes Code agent (write code to a plan; also fixes pre-classified review issues in issue-fix mode) and Skim agent (codebase orientation) — both are defined-execution agents. The feature-knowledge rule (direct delegations only — workflow skills handle their own) instructs the orchestrator to: (1) before delegating non-trivial code work, match the task area against `.devflow/features/index.md` and pass matching KNOWLEDGE.md content as `FEATURE_KNOWLEDGE`; (2) after delegated changes to a covered area, spawn Knowledge (sonnet) to refresh that KB. The charter is 2141 bytes (~535 tokens), well under the 4096-byte runtime cap enforced by the hook. +A static markdown file at `src/assets/scripts/hooks/assets/orchestrator-charter.md` consumed at runtime by `session-start-orchestrator`. Contains the full orchestrator contract: model-tier routing table (haiku/sonnet/opus), judgment-work carve-outs, delegation rules (including a self-contained-delegation operating rule: subagents start with blank context, so every delegation must supply goal, constraints, relevant session decisions and facts, and exact paths — deliverables that draw on the conversation need the substance in the prompt, not a pointer to it), the plan-handoff fallback bullet, and a feature-knowledge operating rule. The never-mainline rule explicitly names codebase orientation as delegated work (alongside file edits, builds, multi-file reads, and debug loops). The sonnet tier routes Code agent (write code to a plan; also fixes pre-classified review issues in issue-fix mode) and Skim agent (codebase orientation) — both are defined-execution agents. The feature-knowledge rule (direct delegations only — workflow skills handle their own) instructs the orchestrator to: (1) before delegating non-trivial code work, match the task area against `.devflow/features/index.md` and pass matching KNOWLEDGE.md content as `FEATURE_KNOWLEDGE`; (2) after delegated changes to a covered area, spawn Knowledge (sonnet) to refresh that KB. The charter is 2452 bytes (~615 tokens), well under the 4096-byte runtime cap enforced by the hook. ### git-marker (sourced helper) @@ -116,7 +116,7 @@ The model-tier routing table (haiku/sonnet/opus taxonomy) is a second intentiona ## Constraints -**4096-byte charter cap**: `session-start-orchestrator` exits silently if the charter exceeds 4096 bytes. The test suite pins the exact-4096-byte boundary as an accept case (the hook uses `-gt 4096`, so 4096 is accepted). Growing the charter beyond this cap silently disables it — always check `${#CHARTER}` after edits. The charter is currently 2141 bytes, leaving ~1955 bytes of headroom. +**4096-byte charter cap**: `session-start-orchestrator` exits silently if the charter exceeds 4096 bytes. The test suite pins the exact-4096-byte boundary as an accept case (the hook uses `-gt 4096`, so 4096 is accepted). Growing the charter beyond this cap silently disables it — always check `${#CHARTER}` after edits. The charter is currently 2452 bytes, leaving ~1644 bytes of headroom. **256-byte prompt head**: The preamble dispatch window is the first 256 bytes post-whitespace-strip. Plan-handoff prompts have zero leading whitespace by definition; the strip is defensive. The window is wide enough for the known prefix but is not semantic detection. @@ -160,7 +160,7 @@ The model-tier routing table (haiku/sonnet/opus taxonomy) is a second intentiona - `src/assets/scripts/hooks/preamble` — UserPromptSubmit hook: dispatch logic, plan-handoff fast-path, orchestrator reminder; cross-reference comment linking to orchestrator-charter.md routing table - `src/assets/scripts/hooks/session-start-orchestrator` — SessionStart hook: charter file read, size guard, hook-log-init injection log, additionalContext output -- `src/assets/scripts/hooks/assets/orchestrator-charter.md` — Static charter content; the plan-handoff fallback bullet, authoritative model-tier routing table, and feature-knowledge operating rule live here +- `src/assets/scripts/hooks/assets/orchestrator-charter.md` — Static charter content; the plan-handoff fallback bullet, authoritative model-tier routing table, self-contained-delegation operating rule, and feature-knowledge operating rule live here - `src/assets/scripts/hooks/git-marker` — Sourced pure-bash helper: `df_has_git_marker ` bounded upward walk; direct behavioral tests + no-subprocess source scan in test suite - `src/cli/commands/ambient.ts` — TypeScript management: `ensureHook`, `addAmbientHook`, `removeAmbientHook`, `hasAmbientHook`, `ambientCommand` (parses settings.json once with try/catch) - `tests/fixtures/ambient-templates.ts` — Shared constants: `HANDOFF_TEMPLATE` and `REMINDER_TEMPLATE`; imported by shell-hooks.test.ts and integration tests to keep both test layers byte-synchronized diff --git a/CHANGELOG.md b/CHANGELOG.md index 96b2e584..db85e030 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed +- **Orchestrator charter — self-contained delegation**: added an operating rule requiring every subagent delegation to be self-contained (goal, constraints, relevant session facts, exact paths). Deliverables that draw on the conversation (issues, PRs, reports) must carry the substance in the prompt rather than a pointer to it. Charter grows from 2177 → 2452 bytes (~600 tokens), well within the 4096-byte runtime limit. + --- ## [2.1.0] - 2026-08-25 diff --git a/CLAUDE.md b/CLAUDE.md index 145a7a49..6d52af43 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -42,7 +42,7 @@ Registry-driven CLI tool with 21 plugins (12 core + 9 optional). Plugins are ent **Working Memory**: A capture/spawn split across always-on hooks in `src/assets/scripts/hooks/`. Toggleable via `devflow memory --enable/--disable/--status` or `devflow init --memory/--no-memory`. Feature state is stored in `.devflow/config.json` (config-only; feature config is the sole source of truth per ADR-001). `capture-prompt` (UserPromptSubmit, always-on) and `capture-turn` (Stop, always-on) — append the user/assistant turn to `.devflow/memory/.pending-turns.jsonl` via the shared `queue-append` helper (dual-write; see Learning pipeline for the sibling learning queue), which uses mkdir-based locking for queue overflow truncation across concurrent sessions; each queue is gated independently by feature config; neither ever spawns anything. `memory-worker` (Stop, registered immediately after `capture-turn` so append-before-spawn ordering holds by array position) — after the 120s throttle (keyed by `.working-memory-last-trigger` mtime), touches the trigger then spawns `background-memory-update` as a detached `nohup` worker (`claude -p --model claude-sonnet-4-6`). `background-memory-update` (detached worker, not a hook itself) — drains `.pending-turns.jsonl`, calls `claude -p` (prompt on stdin, never argv), rewrites `WORKING-MEMORY.md` with `` on line 1, touches `.last-refresh-ok` on success; holds a 300s-stale worker lock; user-only queue truncated without LLM run. `session-start-memory` (SessionStart) → injects previous memory with git-reconciled header (3-state: A in-sync / B drifted / C refresh-failing) + optional pre-compact snapshot as `additionalContext`; stamp `` on line 1 drives drift detection; also recovers a stale orphaned `.pending-turns.processing` itself (self-contained cold path, no external helper). PreCompact hook → saves git state + WORKING-MEMORY.md snapshot. Memory sections: `## Now`, `## Progress`, `## Decisions`, `## Context`, `## Session Log`. The background-memory-update worker uses rename-to-claim for queue consumption (atomically renames `.pending-turns.jsonl` → `.pending-turns.processing`). Disabling memory writes `memory: false` to feature config — hooks remain registered (shared across features). `removeMemoryHooks` (used by `devflow init --no-memory`) also removes legacy hooks from prior architectures. Use `devflow memory --clear` to clean up pending queue files across projects. Zero-ceremony context preservation. -**Ambient Mode**: Two-hook orchestrator system (git repos only) controlled by a single toggle (`devflow ambient --enable/--disable/--status` or `devflow init`). **`session-start-orchestrator`** (SessionStart, presence-gated) — injects the orchestrator charter (~535 tokens) as `additionalContext` at every session start (startup, `/clear`, resume, compact). The charter establishes the main session as a pure orchestrator: delegate work to model-tiered sub-agents (haiku=mechanical, sonnet=defined execution, opus=analysis/design/research) or full devflow workflow skills; keep only judgment work mainline. Also carries a plan-handoff fallback bullet (SessionStart provably fires even when UserPromptSubmit does not). **`preamble`** (UserPromptSubmit, presence-gated) — three behaviors: (1) if prompt begins `Implement the following plan:` (Claude Code's native plan-mode handoff prefix), injects a directive to immediately invoke `devflow:implement`; (2) slash commands (`/...`) are silenced; (3) all other prompts get a 2-line orchestrator reminder. Both hooks are silent outside git repos. Any legacy `commands.md` rule or `session-start-classification` hook from prior installs is auto-removed on every `devflow ambient --enable/--disable` or `devflow init`. +**Ambient Mode**: Two-hook orchestrator system (git repos only) controlled by a single toggle (`devflow ambient --enable/--disable/--status` or `devflow init`). **`session-start-orchestrator`** (SessionStart, presence-gated) — injects the orchestrator charter (~600 tokens) as `additionalContext` at every session start (startup, `/clear`, resume, compact). The charter establishes the main session as a pure orchestrator: delegate work to model-tiered sub-agents (haiku=mechanical, sonnet=defined execution, opus=analysis/design/research) or full devflow workflow skills; keep only judgment work mainline. Also carries a plan-handoff fallback bullet (SessionStart provably fires even when UserPromptSubmit does not). **`preamble`** (UserPromptSubmit, presence-gated) — three behaviors: (1) if prompt begins `Implement the following plan:` (Claude Code's native plan-mode handoff prefix), injects a directive to immediately invoke `devflow:implement`; (2) slash commands (`/...`) are silenced; (3) all other prompts get a 2-line orchestrator reminder. Both hooks are silent outside git repos. Any legacy `commands.md` rule or `session-start-classification` hook from prior installs is auto-removed on every `devflow ambient --enable/--disable` or `devflow init`. **Learning pipeline** (directive-spawned background Learning agent — scripts capture and trigger only): `capture-prompt`/`capture-turn`/`capture-question` (all always-on) append every user turn, assistant turn, and answered `AskUserQuestion` to `.devflow/learning/.pending-turns.jsonl`, gated by the `learning` field in feature config (config-only, mirroring memory's ADR-001). `session-start-context` Section 2 (SessionStart, always-on) — when the learning queue is non-empty, or a crashed run left a `.pending-turns.processing` batch older than 900s, it resolves the model (project `.devflow/learning/learning.json` → global `~/.devflow/learning.json` → `opus` default) and emits a `--- LEARNING MAINTENANCE ---` directive instructing the main model to **silently** spawn `Agent(subagent_type="Learning", model=, run_in_background: true)` **(never narrated in user-visible text)**; a fresh `.processing` suppresses the directive (a live agent owns the batch); queue emptiness is the natural gate, so there is no throttle. The **Learning agent** (`src/assets/agents/learning.md`, opus, self-contained) claims the queue itself (atomic `mv` → `.processing`; merges a stale leftover and re-claims it; exits silently if the claim is lost; heartbeat `touch` at the detection→curation boundary), reads `decisions-log.jsonl`/`decisions.md`/`pitfalls.md`/`.decisions-usage.json` directly, appends/edits observations in the log directly (one JSONL row at a time, never whole-file rewrites), and calls only the ledger ops via its Bash tool: **decision**/**pitfall** detection via `assign-anchor` (internally self-locks `.decisions.lock`; assigns the next ADR-NNN/PF-NNN anchor number into `decisions-ledger.jsonl`, then deterministically renders `decisions.md`/`pitfalls.md`/`index.md` from the ledger — active entries only) and periodic curation via `retire-anchor` (flips `decisions_status`, never deletes) plus `rotate-observations`. Raw observations accumulate in the gitignored `.devflow/learning/decisions-log.jsonl` (rotated to `decisions-log.archive.jsonl`). No deterministic thresholds or confidence formulas — the LLM determines whether an observation warrants a new entry or should be reinforced into an existing one. The agent deletes `.processing` as its final act (consume-then-delete; a crash leaves the batch for the next session's stale-merge recovery) and ends with a 1–3 line summary — native background-task visibility, no status files. Global tuning config: `~/.devflow/learning.json`. Project tuning config: `.devflow/learning/learning.json` (`model` and `debug` only — no daily-run cap or throttle). `devflow learning --disable` flips the config field and drains `.devflow/learning/.pending-turns.jsonl`/`.pending-turns.processing` unconditionally (a mid-run agent whose files vanish aborts without changes — the desired outcome of disabling; mirrors memory.ts's disable-drain). Toggleable via `devflow learning --enable/--disable/--status` or `devflow init --learning/--no-learning`. Management subcommands: `devflow learning --list`, `devflow learning --configure`, `devflow learning --clear/--reset` (both resolve the git root explicitly). diff --git a/src/assets/scripts/hooks/assets/orchestrator-charter.md b/src/assets/scripts/hooks/assets/orchestrator-charter.md index 53083615..cdcd885a 100644 --- a/src/assets/scripts/hooks/assets/orchestrator-charter.md +++ b/src/assets/scripts/hooks/assets/orchestrator-charter.md @@ -16,6 +16,7 @@ Stays mainline (judgment work): conversation, decisions, routing, synthesizing a Operating rules: - Decompose mainline. Subagents cannot spawn subagents — you own task breakdown, then delegate leaf tasks. +- Subagents see none of this conversation. Make every delegation self-contained: goal, constraints, relevant session decisions and facts, exact paths. A deliverable that draws on the conversation (issue, PR, report) needs the substance in the prompt — not a pointer to it. - Parallelize independent delegations in one message. Git operations stay sequential. - Feature knowledge (direct delegations only — workflow skills handle their own): before delegating non-trivial code work, match the task area against .devflow/features/index.md and pass matching KNOWLEDGE.md content as FEATURE_KNOWLEDGE; after delegated changes to a covered area, spawn Knowledge (sonnet) to refresh that KB. - Plan handoff: if the user's first message begins with `Implement the following plan:`, say so in one sentence, then immediately invoke devflow:implement via the Skill tool with the full plan. Do not pause to ask.