| name | insight-forge |
| description | ARA-style cross-session learner for Claude Code AND Codex CLI. Reads JSONL session histories from ~/.claude/projects/ (Claude Code) or ~/.codex/sessions/ (Codex CLI), extracts research-significant events through a 3-stage pipeline (Context Harvester → Event Router → Maturity Tracker), maintains a typed knowledge base under .insight-forge/ (claims, heuristics, dead_ends, exploration_tree), and proposes diffs for CLAUDE.md / AGENTS.md. USER-INVOCABLE ONLY. MANDATORY TRIGGERS (skill must NEVER auto-fire outside these exact formulations): '/insight-forge', 'insight-forge', 'forge insights', 'forge l'insight', 'consolide les sessions', 'consolide les insights', 'mets à jour les insights', 'analyse les sessions précédentes', 'que retient-on des dernières sessions', 'qu'a-t-on appris depuis la dernière fois', 'cristallise les enseignements'. Do NOT trigger on vague paraphrases, git history questions, current-conversation summaries, or any request without one of these exact formulations. |
| allowed-tools | Read, Write, Edit, Bash, Glob, Grep |
Insight Forge
A cross-session, post-hoc, agent-agnostic learner for coding agents.
Reads session transcripts → extracts typed events → maintains a structured knowledge base
→ proposes (never auto-applies) updates to CLAUDE.md / AGENTS.md.
The design is adapted from the Agent-Native Research Artifact (ARA) methodology,
specifically its research-manager skill. Key differences from the original:
- Post-hoc, not end-of-turn. Operates on JSONL transcripts after sessions end.
- Cross-session. Sees the full history, not just the current turn.
- Agent-agnostic. Same pipeline runs over Claude Code OR Codex CLI sessions.
- Provenance reconstructed, not captured live (see
references/provenance-reconstruction.md).
- Devil's Advocate baked in. Every cristallisation must justify a
counter_evidence field.
When This Skill Runs
USER-INVOCABLE ONLY. Never auto-fire. The triggers in the YAML description are exhaustive — anything outside them, do not trigger. In doubt, do not trigger.
This skill writes to a structured knowledge base under .insight-forge/ in the current project. It can also propose a diff to CLAUDE.md (Claude Code) or AGENTS.md (Codex CLI), but never writes to those files directly — proposals land in .insight-forge/proposals/ for the user to review and apply manually.
The 3-Stage Pipeline (ARA-derived)
┌──────────────────────┐ ┌────────────────┐ ┌─────────────────────┐
│ Context Harvester │ -> │ Event Router │ -> │ Maturity Tracker │
│ (extract from │ │ (classify + │ │ (crystallize when │
│ JSONL transcripts) │ │ route) │ │ closure signals) │
└──────────────────────┘ └────────────────┘ └─────────────────────┘
Stage 1 — Context Harvester
Scans the JSONL files of sessions newer than .insight-forge/.last_run (or all sessions on first run). Filters out noise (system-reminders, hooks, bash-input, skill-loading injections — see references/codex-format.md and references/claude-code-format.md for the exact filter rules). Outputs a flat list of candidate events with raw context.
Stage 2 — Event Router
For each candidate, classifies it and tags provenance per references/event-taxonomy.md and references/provenance-reconstruction.md. The dichotomy: journey facts go direct, interpretive claims go staged. Direct events (decisions, experiments, dead_ends, pivots, questions) write immediately to .insight-forge/trace/exploration_tree.yaml. Interpretive events (claims, heuristics, concepts, constraints) go to .insight-forge/staging/observations.yaml.
Stage 3 — Maturity Tracker
Walks staging/observations.yaml and decides which staged observations are mature. Cristallisation requires at least one of four closure signals (per references/crystallization-rules.md):
- Topic abandonment — N+ sessions idle without revisit
- Verbal affirmation — explicit user endorsement in transcript
- Empirical resolution — tool execution confirmed/refuted the observation
- Artifact commitment — code/config now depends on the observation
Default to non-promotion. Premature crystallisation pollutes the knowledge base and is the failure mode this design exists to prevent.
When promoting, also generate a counter_evidence field — the Devil's Advocate clause (see references/devils-advocate.md). If no counter-evidence can be articulated, mark as counter_evidence: not_explored and treat as warning.
Per-Run Procedure
Single command — the orchestrator handles everything:
python3 scripts/run.py [--project $(pwd)] [--forge-dir .insight-forge]
run.py wires the full pipeline automatically:
- Reads
.insight-forge/.last_run to get the cursor timestamp
- Detects which agent(s) are present (
~/.claude/projects/ and/or ~/.codex/sessions/)
- Calls the right extractor(s) with
--since <last_run> — only new sessions are read
- Merges outputs into
.insight-forge/.cache/normalized.jsonl
- Runs
pipeline.py (Harvester → Router → Maturity Tracker)
- Runs
propose_claude_md.py → .insight-forge/proposals/<date>.md
- Updates
.last_run
- Prints one-line summary
If .last_run does not exist (first run), all sessions are processed. On every subsequent run, only sessions modified after .last_run are extracted — previously processed JSONL files are never re-read.
Available flags:
--rebuild Ignore .last_run, reprocess all sessions from scratch
--since ISO8601 Override .last_run with an explicit date
--agent claude|codex Force a specific agent (default: auto-detect both)
--challenge Run Devil's Advocate sweep after crystallization
--fuzzy-cwd Codex: include parent/child cwd sessions
--exclude-session ID Codex: exclude session by id prefix (repeatable)
--active-grace SECONDS Codex: skip sessions modified within N seconds (default: 60)
ARA Directory Structure (under .insight-forge/)
.insight-forge/
├── INSIGHTS.md # Root manifest + layer index (~200 tokens)
├── .last_run # ISO timestamp + last-processed session_id
├── .cache/
│ ├── normalized.jsonl # Pivot schema, regen on each run
│ └── facets.json # Optional: read /insights cache if available
├── logic/ # What & Why (crystallized only)
│ ├── claims.md # Falsifiable assertions + proof refs
│ ├── heuristics.md # Implementation tricks + rationale + sensitivity
│ ├── dead_ends.md # First-class — failure modes + lessons
│ └── concepts.md # Formal definitions
├── trace/ # Journey (direct routing)
│ ├── exploration_tree.yaml # DAG: decisions/experiments/dead_ends/pivots
│ ├── session_index.yaml # One entry per scanned session
│ └── pipeline_log.yaml # Self-continuity: pipeline's own decisions
├── staging/
│ └── observations.yaml # The crystallisation buffer
├── evidence/
│ ├── README.md
│ └── sessions.html # iMessage-style annex (rendered on demand)
└── proposals/
├── claude_md_diff_<date>.md # Or AGENTS.md depending on agent
└── README.md
Schemas
Exploration Tree Node — trace/exploration_tree.yaml
tree:
- id: N01
type: question | decision | experiment | dead_end | pivot
title: "{short title}"
provenance: user | ai-suggested | ai-executed | user-revised
timestamp: "YYYY-MM-DDTHH:MM"
session_id: "{8-char prefix}"
description: >
choice: >
alternatives: []
evidence: []
result: >
hypothesis: >
failure_mode: >
lesson: >
could_have_worked_if: >
from: ""
to: ""
trigger: ""
status: open | resolved | unresolved
children: []
also_depends_on: [N{XX}]
Claim — logic/claims.md
## C{XX}: {title}
- **Statement**: {falsifiable assertion}
- **Status**: hypothesis | supported | weakened | refuted | revised
- **Provenance**: user | ai-suggested | user-revised
- **Crystallized via**: topic-abandonment | verbal-affirmation | empirical-resolution | artifact-commitment
- **Counter-evidence**: {what would refute this — Devil's Advocate} | not_explored
- **Falsification criteria**: {what would disprove this}
- **Proof**: [{evidence refs or "pending"}]
- **Dependencies**: [C{YY}, ...]
- **Tags**: {comma-separated}
- **From staging**: O{XX}
- **Sessions**: [{session_id 8-char prefixes}]
Heuristic — logic/heuristics.md
## H{XX}: {title}
- **Rule**: {short imperative}
- **Rationale**: {why it works}
- **Provenance**: user | ai-suggested | user-revised
- **Crystallized via**: {closure signal}
- **Sensitivity**: low | medium | high
- **Code refs**: [{file paths or "pending"}]
- **Counter-cases**: {when does this NOT apply — Devil's Advocate}
- **From staging**: O{XX}
- **Sessions**: [{session_id prefixes}]
Dead End — logic/dead_ends.md
## D{XX}: {title}
- **Hypothesis tested**: {what was tried}
- **Failure mode**: {how it broke}
- **Lesson**: {takeaway, single sentence}
- **Could have worked if**: {Devil's Advocate clause — what missing piece could have rescued this}
- **Provenance**: user | ai-suggested | ai-executed | user-revised
- **Code refs**: [{file paths affected}]
- **Sessions**: [{session_id prefixes}]
- **Avoid signal**: {phrase that should make Claude/Codex avoid this in future}
Observation — staging/observations.yaml
observations:
- id: O{XX}
timestamp: "YYYY-MM-DDTHH:MM"
provenance: user | ai-suggested | ai-executed | user-revised
content: "{distilled observation}"
context: "{what was happening in the session}"
potential_type: claim | heuristic | concept | constraint | architecture | dead_end | unknown
bound_to: [N{XX}, ...]
promoted: false
promoted_to: null
crystallized_via: null
stale: false
last_referenced: "YYYY-MM-DD"
session_id: "{8-char prefix}"
Session Index — trace/session_index.yaml
sessions:
- id: "{8-char prefix}"
full_id: "{full UUID}"
agent: claude | codex
date: "YYYY-MM-DD"
cwd: "{project path}"
turn_count: {N}
file_size_kb: {N}
summary: "{one-line synthesis}"
events_extracted: {N}
observations_staged: {N}
crystallizations: {N}
contradictions_flagged: {N}
Pipeline Log — trace/pipeline_log.yaml
A few lines per run explaining the pipeline's organisational decisions. Cheap on tokens, prevents organisational drift across runs.
runs:
- run_id: "YYYY-MM-DDTHH:MM"
sessions_processed: [{session_id prefixes}]
notes:
- "Staged O07 as potential_type: heuristic — it's a how, not a what."
- "Did NOT crystallize O05 despite affirmation-like language: user said 'maybe'."
- "Routed N12 as dead_end — code was abandoned mid-run, never revisited."
Initialization (if .insight-forge/ does not exist)
Only initialize on a triggered run. Don't ask unprompted.
mkdir -p .insight-forge/{logic,trace,staging,evidence,proposals,.cache}
Then seed:
INSIGHTS.md — root manifest (infer project from cwd and any existing CLAUDE.md/AGENTS.md)
trace/session_index.yaml — sessions: []
trace/exploration_tree.yaml — tree: []
trace/pipeline_log.yaml — runs: []
staging/observations.yaml — observations: []
logic/claims.md — # Claims
logic/heuristics.md — # Heuristics
logic/dead_ends.md — # Dead Ends
logic/concepts.md — # Concepts
evidence/README.md — # Evidence Index
proposals/README.md — # Proposals
.last_run — empty
Add .insight-forge/ to .gitignore only if user requests — by default, the user may want to version it.
Run Modes
/insight-forge (default)
Full pipeline: scan since .last_run → extract → route → mature → propose. End with one-line summary and pointer to proposals/<date>.md.
/insight-forge --challenge
Non-tautological Devil's Advocate sweep over already-crystallized claims. For each status: supported claim, run the 6-axis projection (accessibility, performance, security, maintenance, legal, organizational — see references/devils-advocate.md) and search NEW sessions for evidence on each axis. Prioritize entries the quadrant mapping flags as Déni. Does not modify claims directly — flags only.
/insight-forge --council <entry_id>
The big one. Submits a single cristallized entry to 5 structurally incompatible attackers: Falsificationniste, Pré-mortem, Inverseur, Contraintes-First, Second-Ordre. Then a Procureur synthesizes the verdict. See references/council-protocol.md for the protocol.
Workflow:
scripts/council.py --entry C03 writes 6 prompt files into .insight-forge/council/C03-<date>/
- The agent (Claude Code or Codex CLI) reads
council/C03-<date>/README.md and spawns 5 sub-agents IN PARALLEL via its native sub-agent system (Task tool for Claude Code, sub-agent for Codex)
- Each sub-agent's response is saved to
attack-XX-*.md
- The agent fills the placeholders in
06-procureur.prompt.md with the 5 responses, runs a 6th call, saves the result to verdict.md
- The user reads
verdict.md and decides whether to update the entry
Hard cost-discipline: one council per entry per 30 days unless --force. The --council all syntax is intentionally absent — single entry only.
/insight-forge --evidence <entry_id>
Render a focused HTML iMessage view of just the sessions that fed a specific claim/heuristic/dead_end. Output to evidence/sessions-<id>.html.
/insight-forge --rebuild
Discard .insight-forge/ (after confirmation prompt) and reprocess everything from scratch. Useful when filter rules or schemas evolve.
/insight-forge --since YYYY-MM-DD
Override .last_run and process from a specific date. Useful for backfill.
Rules
- USER-INVOCABLE ONLY. Never run on auto-pilot. Verify a trigger phrase appeared in the user's message before proceeding.
- Never fabricate events. Only log what actually happened in the JSONL.
- Stage by default. Claims, heuristics, concepts, constraints, architecture statements pass through staging.
- Never crystallize without a closure signal. No counters, no LM-judged maturity — abandonment / affirmation / resolution / commitment only.
- Never auto-upgrade provenance.
ai-suggested stays until verbatim user affirmation.
- Never silently overwrite contradictions. Flag both, append unresolved decision node, defer.
- Always read existing files first. Get correct next IDs, avoid duplicates.
- Establish forensic bindings. claim→proof, heuristic→code, decision→evidence. Use
[pending] + TODO if not yet bindable.
- Append, never overwrite. New entries only; status updates use Edit on the specific field.
- Devil's Advocate always. Every crystallisation must produce
counter_evidence (or not_explored flagged).
- Never auto-edit
CLAUDE.md or AGENTS.md. Only write to .insight-forge/proposals/.
- Be terse in summaries. One line per run, factual.
- Filtered transcripts only. See
references/codex-format.md and references/claude-code-format.md for the noise filter rules.
- Cross-platform paths. Use
~ resolution and Path operations — Windows D:\ vs POSIX /Users/.
Reference files
references/event-taxonomy.md — kind classification, direct-vs-staged decision tree, skip filter
references/crystallization-rules.md — 4 closure signals + procedure + contradiction trigger
references/provenance-reconstruction.md — post-hoc rules to infer provenance from transcript
references/contradiction-protocol.md — what to do when an event contradicts staged/cristallized
references/devils-advocate.md — required Devil's Advocate clauses, hedging detection lint, the 6-axis sweep, and the non-tautological --challenge mode
references/known-unknown-mapping.md — Rumsfeld matrix as orthogonal grid (Ancrage/Brouillard/Déni/Abîme), routing logic for proposals and challenge prioritization
references/council-protocol.md — 5-attacker protocol for --council mode
references/codex-format.md — Codex CLI JSONL spec + filter rules
references/claude-code-format.md — Claude Code JSONL spec + filter rules
Scripts
User-facing entry point — what the skill invokes when triggered:
scripts/run.py — single-command orchestrator. Reads .last_run, calls the right extractor(s) with --since, runs the pipeline, generates the proposal, prints the friendly summary, updates the cursor. This is what the skill calls. Everything else below is invoked transitively by it.
Pipeline internals (called by run.py):
scripts/extract_claude.py — locate ~/.claude/projects/<encoded-cwd>/*.jsonl, output filtered events
scripts/extract_codex.py — locate ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl, filter by <environment_context> cwd
scripts/pipeline.py — Harvester → Router → Maturity, the ARA core. Lazy-loads classifier rules from harness/rules.yaml. Writes evidence bundles to .insight-forge/evidence/bundles/.
scripts/render_evidence.py — iMessage-style HTML annex (adapted from creation-autopsy)
scripts/propose_claude_md.py — generate the diff proposal. Splices quotes from evidence bundles into the markdown; prints the friendly summary on stderr.
On-demand modes (user-invocable through run.py flags):
scripts/council.py — prepare a 5-attacker council session for a single entry (no LLM calls itself; agent orchestrates)
Contributor tooling (not invoked by the skill — for maintaining the project itself):
scripts/run_evals.py — regression eval harness. Runs synthetic transcripts under evals/fixtures/ through the pipeline and asserts behavior. --verify-contracts validates each rule against its must_fire_on / must_not_fire_on fixtures.
scripts/propose_rules.py — eval-graded mutation search over harness/rules.yaml. Generates candidate edits to classifier rules; writes proposals to harness/proposals/. Never auto-applies.
Compatibility
The skill is dual-target. Place at:
- Claude Code:
~/.claude/skills/insight-forge/ (user) or <project>/.claude/skills/insight-forge/ (project)
- Codex CLI:
~/.codex/skills/insight-forge/ (user) or <project>/.codex/skills/insight-forge/ (project)
Trigger phrases work identically. The agent detection step at the start of the pipeline auto-routes to the right extractor.
Failure modes to expect
- Codex sessions sharded by date, not project. Filtering by cwd is approximate (lives in
<environment_context>). Some sessions might be missed if the cwd block was malformed.
- Auto-compaction. Long Claude Code sessions get compacted — some messages will be missing. The pipeline must tolerate gaps.
- Renamed/moved projects. Old sessions stored under the old encoded-cwd are unreachable unless user provides a hint.
- Subagents. Subagent transcripts are excluded by default (signal-to-noise too low).
- Staging that never crystallizes. Observations can sit forever in staging if no closure signal fires. The
stale: true flag after 14 days surfaces them at next run for triage.