Imported from parsoFish/forge-studio (
skills/reflector/SKILL.md). Install upstream withnpx skills add parsoFish/forge-studio --skill reflector. Copyright stays with the author.
Reflector
Single responsibility
Close the learning loop. After an initiative is merged, run the four-stage retro (per docs/phases/reflection.md) and write findings into the brain by direct file writes — theme markdown files under brain/projects/<project>/themes/ plus a cycle archive under brain/cycles/_raw/<cycle-id>.md.
Operator handoff (the reflection human moment)
The in-UI /reflect screen is the operator surface (ADR 023): it renders the user-questions.json this skill emits, writes user-feedback.md, and the bridge auto-reruns the reflector. In interactive mode (the default) the feedback is supplied by a human. In automated mode (R4-09-F3, selected by the trigger's mode: automated) there is no human: the reflector infers each answer from the cycle logs / demo / diff and self-answers with inferred: true provenance — the per-cycle brief's Stage 2/3 tells you which mode you are in and exactly what to write.
Reads: _logs/<id>/user-questions.json (≤4 entries; [] if none written); _logs/<id>/retro.md + _logs/<id>/events.jsonl for context.
Writes: _logs/<id>/user-feedback.md — answer each numbered question, then add free-form feedback. Stage 3 distils this into retro.md Section 2 (answers) + Section 3 (free-form). Contract: orchestrator/phases/reflector-binding.ts, orchestrator/phases/reflector.ts. If the file is absent when the reflector runs, record _(no feedback supplied this cycle)_ and continue.
Required first action
Invoke brain-query BEFORE writing anything (ADR 010). First tool calls MUST be Read/Grep/Glob against brain/... or brain/projects/<project>/... paths — at minimum brain/projects/<project>/profile.md and any prior brain/projects/<project>/themes/*.md matching a pattern observed in the event log. The orchestrator records tool_use.brainReads and fails the reflection if zero brain reads are recorded (production gates on brain_consulted). Unconditional, not "when unsure".
Inputs
_logs/<cycle-id>/events.jsonl— full cycle log._logs/<cycle-id>/brain-gaps.jsonl— questions the brain couldn't answer (may be empty/missing — tolerate).- Merged project tree (read-only inspection for code patterns).
- The merged PR (R4-09-F2): its description at
<worktree>/.forge/pr-description.md(the stated intent), thereviewer.pr-openedevent (PR url), and thedev-loop.delivereddiff-stats (what actually shipped). Nogh— read the file + the events. - Existing brain knowledge (prior retros, established patterns).
Outputs
_logs/<cycle-id>/retro.md— three sections:## Self-reflection,## User questions,## User feedback.- Theme pages in
brain/projects/<project>/themes/<YYYY-MM-DD>-<slug>.md— one file per significant pattern. Required frontmatter:title,description,category,keywords(flow-style list of 5–10 lowercase search terms — feeds brain-query slug/one-liner matching and the contradiction lint),created_at,updated_at, andrelated_themes(flow-style list of sibling theme slugs — see Stage 4 linking;[]only if genuinely standalone).keywordsandrelated_themesare mandatory, not best-effort: a prior reflector run dropped both and never indexed its themes, costing a 132-theme brain all of its theme↔theme edges (ADR 018). Body must include## Sourceslisting ≥1 path resolving to_logs/<cycle-id>/...orbrain/cycles/_raw/<cycle-id>.md, and — whenrelated_themesis non-empty — a## See alsosection mirroring it as[[slug]] — whybullets. This matches the canonical format inbrain/cycles/themes/README.md. brain/cycles/_raw/<cycle-id>.md(cycle log archived). Required frontmatter (write these placeholder values exactly — the orchestrator post-processes to computeretentionand populatecited_by; do NOT compute these yourself):
Body: short summary plus the full event-log excerpt (or a link).--- source_type: cycle source_url: _logs/<cycle-id>/events.jsonl source_title: Cycle <cycle-id> — Initiative <initiative-id> cycle_id: <cycle-id> initiative_id: <initiative-id> project: <project> ingested_at: <ISO-8601 timestamp> ingested_by: reflector retention: auto cited_by: [] ---_logs/<cycle-id>/user-questions.md(stage 2; write unless literally zero deliverables). Use## N. <header>headings. The orchestrator derivesuser-questions.jsonpost-exit._logs/<cycle-id>/user-questions.json— do NOT write this yourself; derived by the orchestrator fromuser-questions.mdpost-exit.
The reflector does NOT move the manifest to _queue/done/ — the reviewer already did that.
Event-log entries to emit
reflector.startreflector.brain-query(per query)reflector.self-reflection-completereflector.user-question-emitted(per question written intouser-questions.md)reflector.user-feedback-capturedreflector.theme-emitted(per theme file written)reflector.lint-pass-clean(after structural validation passes)reflector.end
Process
Stage 1 — Agentic self-reflection (unattended)
Scope: the WHOLE initiative, not just the closing cycle (DEC-2). The spine (forge-architect → forge-develop → this post-merge reflect run) threads ONE
cycle_id, soevents.jsonlholds the architect/PM decompose, the dev-loop build, and the review for the entire initiative. Reflect across all of it.
- Brain query first.
- Read the full event log. Compute: iterations per WI/feature/initiative; cost by phase/skill/model; wedge events, recovery events, brain-gap counts, send-back rounds.
- Repeated actions — find actions the agents took more than once across the initiative (re-running the same gate, re-editing the same file, re-opening a PR, re-deriving the same fact, retrying the same command). A repeated action is a signal of a missing tool, a stale convention, or an unclear spec — name each one with its count.
- Roadblocks / wedges — find where the cycle stalled, wedged (
wedgeevents), burnt tokens with no tool progress, hit a rate limit, or needed a recovery/resume. For each, capture what unblocked it (or that it stayed blocked). 4b. Review the PR (R4-09-F2). Read<worktree>/.forge/pr-description.mdfor the PR's stated intent, then cross-reference the shipped diff (dev-loop.deliveredstats + the merged tree). Note where the delivered code diverges from the stated intent (scope drift, dropped ACs, extra changes) — this is the grounding for the implementation-vs-design question in Stage 2, and every Stage-2 question must cite a concrete PR/log specific (a changed file, a PR claim, an event count), never a generic template. - Identify notable patterns — worked unusually well, wedged or burnt token, antipatterns observed.
- Delivery truth = the
dev-loop.delivered/dev-loop.discardedevents (git diff-stat) + the merged tree, NOT per-WI status counts.dev-loop.deliveredfires ONLY for a WI that shipped (outcome: 'complete'); a failed WI's diff-stat carries the SAME fields ondev-loop.discarded(outcome: 'failed') — attempted but not delivered. Per-WIstatus: failedcan be stale after a resume. Never conclude "nothing delivered / empty branch" ifdev-loop.deliveredshowsfiles_changed > 0. If status and diff disagree, the diff wins — and that contradiction is itself the antipattern worth a theme (stale-status-vs-real-delivery), not "the PR was empty" (cascade-v4 #1).
- Delivery truth = the
- Draft Section 1 of
retro.md(## Self-reflection) — concrete observations, no hand-waving. Lead with the repeated actions and roadblocks found in 3-4 (or_(none observed)_for either).
Stage 2 — Agent-prompted user questions (file-based handoff)
Do NOT call AskUserQuestion. Write questions to user-questions.md only; the orchestrator derives user-questions.json post-exit.
Mode (R4-09-F3). In automated mode the per-cycle brief additionally directs you to write an
**Inferred answer:** <answer> — <citation>line under each question (inferred from the logs/demo/diff, never fabricated) and to self-writeuser-feedback.md. The orchestrator stampsinferred: trueper answer inuser-questions.json. In interactive mode (default) follow the human-handoff steps below unchanged.
Before writing anything, read _logs/<cycle-id>/user-feedback.md if it exists (this is a rerun — the operator already answered a prior question set). For each candidate question below (seed or Stage-1-derived), check whether user-feedback.md already answers it — same question, a paraphrase of it, or the underlying open item it was probing. Do NOT re-emit a question user-feedback.md already answers. Only genuinely new/unanswered questions may be written to user-questions.md. If every candidate is already answered, write _logs/<cycle-id>/user-questions.md with a single line — _(no open questions — prior feedback covers this cycle)_ — instead of the seed set; do not pad back up to 4 with already-answered questions just to hit a count.
-
From Stage 1, identify items you cannot resolve from established principles + brain knowledge. These become user questions.
-
Write up to 4 structured questions into
_logs/<cycle-id>/user-questions.md(## N. <header>per question). Each question is a## N. <header>heading, a one-line body, then (optionally) a markdown bullet list of choices — the orchestrator renders a bullet list as radio options and a question with no bullets as a freeform textarea.Guaranteed seed questions — include these four unless literally zero deliverables or
user-feedback.mdalready answers them (see above):- "Was the work-item decomposition the right size?" (bullets: too-few, right-sized, too-many)
- "Did the implementation match the design intent and stay on the initiative's goals?" (bullets: exact match, minor divergence, scope drift)
- Repeated actions / roadblocks — surface the specific repeated actions + roadblocks you found in Stage 1 and ask which is worth a forge fix or a new tool (bullets drawn from the actual findings, e.g. the most-repeated action, the worst wedge, "none — leave as-is").
- General notes — a freeform question (NO bullet list) inviting any other operator notes on this initiative.
Replace a seed with a sharper project-grounded follow-up only when Stage 1 gives a more pointed version of the same question; keep #4 freeform. Cap at 4 total, minus whatever
user-feedback.mdalready covers. -
Capture user answers (from
user-feedback.mdin stage 3) as Section 2 ofretro.md.
Stage 3 — Pure user feedback (file-based handoff)
- Read
_logs/<cycle-id>/user-feedback.md. - If present, distil answers into Section 2 and free-form text into Section 3 (
## User feedback). If absent, write_(no feedback supplied this cycle)_for both.
Stage 4 — Brain writes (unattended)
-
For each notable Stage-1 observation, write a theme file scoped to the right brain (Q5-B — route by the lesson's SUBJECT, per the three-brain model, ADR 018). Two routing decisions apply, in order:
(a) Project-specific vs forge-wide. Lesson about this project (code, conventions, domain, a bug) → its project KB
brain/projects/<project>/themes/<YYYY-MM-DD>-<slug>.md. Lesson about forge machinery (orchestrator, gate behaviour, Ralph loop, scheduler, PM/reflector behaviour) → forge-wide, one of the two dirs in (b). Litmus test: "would this lesson be true for a DIFFERENT project too?" If yes → forge-wide, NOT Brain 3.(b) For forge-wide themes, category decides the sub-wiki — this is enforced by
checkCategoryScope(cli/brain-lint.ts) and a mismatch is a lint error, not a style choice:categoryfrontmatterBrain dir patternbrain/cycles/themes/antipatternbrain/cycles/themes/operationbrain/cycles/themes/decisionbrain/forge-dev/themes/referencebrain/forge-dev/themes/Set
categoryfirst, then place the file per this table — do not default adecisionorreferencetheme intobrain/cycles/themes/(a real rerun mis-routed adecision-category theme there; caught only by hand-runningcheckCategoryScope). Project-scoped themes (a) are exempt from this table — they always go underbrain/projects/<project>/themes/regardless of category.- Required frontmatter +
## Sourceslisting ≥1 path resolving to the cycle log or archive.
- Required frontmatter +
-
Link + index the new theme (do not leave it an island). You already read the prior related themes in Stage 1 — record the connection instead of discarding it into prose:
related_themes: set it to the slugs of the prior themes this one extends, repeats, or contradicts (e.g. the earlier cycle in a recurring saga, or the topical*-indexhub page for its cluster). For each slug you add, add the reciprocal entry to that theme'srelated_themestoo, and add a## See also[[slug]] — whybullet to both. A brand-new standalone lesson may userelated_themes: [].- Category index: append the theme's one-line entry (
- [\`](./themes/.md) —) under the### Auto-linkedtail of the owning category index in the same brain dir —patterns.md/antipatterns.md/decisions.md/reference.md(project brains carry these four; create the file from the cycles-index template if absent). This is whatcheckCategoryIndex` gates and what brain-query reads first.
-
Archive the cycle log to
brain/cycles/_raw/<cycle-id>.mdwith full provenance frontmatter. -
Validate: every theme file has valid frontmatter (incl.
keywords+related_themes) + validcategory+ ≥1 resolvable evidence path + a category-index entry + reciprocalrelated_themes. Fix before exiting.
Direct-write brain. The reflector writes theme files directly;
brain-ingestis NOT invoked. The orchestrator callsregenerateBrainIndexafter you exit — that regeneratesbrain/INDEX.mdonly, not the per-category indexes; you maintain those (step 11). Do not updatebrain/INDEX.mdyourself.
Constraints
- Brain query first. Zero brain reads before writes = reflection fails (production gates on
brain_consulted). - Concrete actions, not vague intentions. "We could improve X" rejected. "X happened N times; new theme page Y added; antipattern Z indexed" required.
- Evidence-grounded themes. Every theme MUST cite ≥1 source path resolving to
_logs/<cycle-id>/...orbrain/cycles/_raw/<cycle-id>.md. - One theme per file. Don't combine unrelated lessons.
- No queue mutation.
_queue/done/already contains the manifest. Read-only. - No
ghoperations. The reviewer already merged. - No web tools.
WebFetch/WebSearchare disabled.
Output style
S8 / C25 — micro-caveman directive (per-phase, NOT global). Theme drafts are operator-iterated; brevity = signal. Forge-internal only.
- Drop articles, filler ("just", "really", "basically"), pleasantries, hedging.
- PRESERVE code, function names, error strings, paths, file references byte-perfect.
- DO NOT compress: security warnings, irreversible-op confirmations, PR descriptions.
- When in doubt, prefer terse.