After Dream RunLoop completes, runPostLoopTier1Forge collects recent
Claude session JSONL files (modified in last 26h, >1KB) from
~/.claude/projects/ and runs llm.RunForgeTier1 to produce draft
session pages in .agents/ao/sessions/.
Config: reads dream.local_curator.model and dream.local_curator.ollama_url
(same config the curator adapter uses). When no model is configured, the
hook skips silently (opt-in). AGENTOPS_FORGE_TIER1_DISABLE=1 kill switch
also short-circuits.
Results are recorded in the morning report's close_loop.tier1_forge
object (files_processed, files_skipped, sessions_wrote, errors). All
errors degrade honestly into summary.Degraded; the Dream run never
aborts on Tier 1 failure.
Tests:
- collectRecentSessionJSONL finds recent .jsonl, skips tiny/non-jsonl
- No ~/.claude/projects/ returns nil (no error)
- Kill switch skips silently
- No model configured skips silently
Learnings extracted from the Tier 1 forge implementation session.
Next work harvested: W5 Dream hook, W6 Tier 2 gate, flag matrix
test fix, larger chunk spike.
cli/cmd/ao/forge.go (thin cobra wiring, 32 lines added):
- New flags: --tier, --model, --llm-endpoint on forge transcript
- runForgeTranscript branches to runForgeTier1 when --tier=1
- runForgeTier1 helper calls llm.RunForgeTier1 with OutputDir set to
<cwd>/.agents/ao/sessions/
- --tier=1 without --model returns an immediate error
- Default --llm-endpoint empty → llm.ResolveDefaultEndpoint()
(reads $AGENTOPS_LLM_ENDPOINT, falls back to http://localhost:11434 —
NOT hardcoded per pre-mortem F6)
cli/internal/llm/redactor.go + test:
- Prefix-match secret redactor (AWS, GitHub PAT/OAuth, Anthropic,
OpenAI, PEM private key blocks)
- Home-path scrubbing to /FIXTURE
- 8 test cases including credential-at-chunk-boundary (F3 critical)
cli/internal/llm/forge_tier1.go + test:
- RunForgeTier1(opts) dispatcher chaining:
parser → Redact (BEFORE chunking, F3) → ChunkTurns →
Summarizer.SummarizeChunk → BuildPage → WriteSessionPage
- Kill switch: AGENTOPS_FORGE_TIER1_DISABLE=1 short-circuits immediately
- Tier1Options.SetGeneratorFactory enables test injection of a fake LLM
- Per-chunk errors degrade honestly to a skipped chunk (confidence drops)
- L2 integration test via httptest.NewServer asserts:
- Full end-to-end: fixture JSONL → session page on disk
- stream:false in /api/generate body
- GitHub token in fixture does NOT appear in the written page
- Kill switch halts the pipeline
- Missing OutputDir/SourcePaths return clear errors
- FactoryInjection path for fakeLLM (test-only backend)
All llm package tests green (25+ cases across chunker, ollama, summarizer,
session writer, redactor, forge_tier1). cd cli && go build ./... clean.
Part of jsonl-to-llm-wiki tiered forge v1 slice (W0-W4+W7). Next: W7
local commits + pre-push gate, PAUSE before PR per plan.
Summarizer: renders each TurnChunk into the spike-validated PromptTemplate
(verbatim copy from .agents/rpi/spike-2026-04-11-gemma4-output-shape.md
— DO NOT edit without re-running the spike), calls the LLM once, tolerates
a wrapping ```markdown fence, and parses the strict-markdown output into
a ChunkNote (Intent / Summary / Entities / AssistantCondensed). Returns
an error when any required section is missing or empty. Recognizes "SKIP"
as a valid non-substantive response.
Session writer: 17-field frontmatter SessionFrontmatter struct enumerates
every field from the council ARCH-3 schema (type, session_id, source_jsonl,
workspace, started_at, ended_at, turns, tokens_in/out, model_primary,
status, tier, model, model_digest, confidence, ingested_at, ingested_by,
first_seen, + optional parent_session/reviewed_at/reviewed_by). BuildPage
computes confidence from the skip ratio and defaults status=draft, tier=1.
WriteSessionPage writes to a sibling tempfile then os.Rename's it into
place (atomic per pre-mortem F2).
Generator interface narrows what Summarizer needs from an LLM backend so
tests can use a fakeLLM scripted with canned responses; *OllamaClient
satisfies it via the new ModelName() method.
Tests (fakeLLM + tempdir):
- Strict-markdown parse on the real spike output
- SKIP recognition
- ```markdown fence tolerance
- Missing-section error
- LLM error propagation
- Prompt contains verbatim spike template + USER/ASSISTANT rendering
- Entity wikilink extraction
- Full 17-field frontmatter serialization
- Optional fields omitted when empty
- Atomic WriteSessionPage (no temp file leftover)
- Overwrite via atomic rename
- BuildPage confidence from skip ratio
Part of jsonl-to-llm-wiki tiered forge v1 slice. W4 wires RunForgeTier1
into cli/cmd/ao/forge.go as a ≤40 LOC thin dispatcher that chains:
parser → redactor → ChunkTurns → Summarizer.SummarizeChunk (per chunk) →
BuildPage → WriteSessionPage.
New cli/internal/llm package with TurnChunk type and ChunkTurns(msgs,
maxChars) that groups TranscriptMessages into budget-bounded user→
assistant chunks. Drops tool_use/tool_result noise, filters <20-char
messages, proportionally truncates oversized pairs (40/60 user/assistant).
Test-first: 11 unit tests covering empty input, single pair, multi-pair,
budget boundaries (500/2000/4000), orphan drop, tool-noise filter, prompt
rendering, and zero-budget default fallback.
Part of the jsonl-to-llm-wiki tiered forge v1 slice. Downstream waves
(ollama client, summarizer, session writer, forge wiring) consume
TurnChunk via .Prompt() or field access. Privacy redaction runs BEFORE
chunking per pre-mortem F3 and is owned by W4.
Empirical basis: .agents/rpi/spike-2026-04-11-gemma4-output-shape.md (3/3
PASS on real nami session chunks with gemma2:9b).
NewOllamaClient(opts) probes /api/tags to validate model installation,
records the model digest (for frontmatter model_digest field), and
queries /api/show to determine the advertised context budget (falling
back to DefaultContextBudget on any failure). Generate() POSTs to
/api/generate with stream:false (critical — ollama's default is
stream:true which would break single-shot JSON decode), retries on 5xx
up to MaxRetries, and returns the response string.
Sentinel errors: ErrOllamaOffline (connection refused), ErrModelNotInstalled
(model absent from /api/tags).
ResolveDefaultEndpoint() reads $AGENTOPS_LLM_ENDPOINT or falls back to
http://localhost:11434 — not hardcoded to bushido per pre-mortem F6.
Tests (httptest.NewServer mocks, 10 cases):
- stream:false asserted in request body (S6 critical)
- ErrModelNotInstalled when /api/tags omits the model
- ErrOllamaOffline on connection refused
- Digest() returns /api/tags digest value
- ContextBudget() uses /api/show model_info.*.context_length
- ContextBudget() falls back to DefaultContextBudget on missing field
- Generate() retries once on 5xx
- Malformed JSON surfaces a decode error
- Per-request timeout fires via SetRequestTimeout
- ResolveDefaultEndpoint env override + fallback
Part of jsonl-to-llm-wiki tiered forge v1 slice. W3 summarizer consumes
OllamaClient via Generate(prompt) and stamps Digest()/ContextBudget()
into the session page frontmatter.
Proposes a new skill `skills/llm-wiki/` that brings Andrej Karpathy's LLM
Wiki pattern (April 2026) into AgentOps as a compounding layer for
external knowledge (articles, papers, transcripts, clipped web content).
Complements existing flywheel skills:
- skills/compile operates on internal .agents/ artifacts (existing)
- skills/llm-wiki operates on external raw/ sources (proposed)
Both produce LLM-maintained markdown wikis; they cross-link but don't
merge. The skill is tier-agnostic (--tier 1|2|3 flag for always-on local
LLM / on-demand expert / human).
Contents:
- skills/llm-wiki/SKILL.md — skill specification with init/ingest/query/
lint/promote phases, interop with compile/research/forge/inject/
post-mortem/knowledge-activation, output contract, open questions
- skills/llm-wiki/references/architecture.md — full design rationale,
3-tier curator model, anti-patterns, schema files, migration path
- skills/llm-wiki/references/research.md — research artifact with source
analysis (Karpathy gist, 2 community implementations, ecosystem tools)
Status: PROPOSAL. No implementation yet. Council review via
/pre-mortem --preset=product recommended before any code is written.
Motivated by real use on bushido-box (Boful's personal dev box) where
the vault needed a compounding external-knowledge layer to complement
the existing AgentOps internal flywheel. See
platform-lab/patterns/llm-wiki-architecture.md in that vault for the
host-specific design this proposal abstracts.
Treat successful Windows process lookup as alive instead of using unsupported Unix signal(0), and include the overnight package in the native Windows smoke gate.
Adds a blocking windows-smoke job, native PowerShell smoke script, Windows docs updates, and moves a Unix-only RPI lock permission test out of the Windows test path.
Adds a Windows PowerShell installer for ao, documents the Windows install path, fixes Windows-specific ao/runtime test issues, and removes the CI ripgrep dependency from the Codex override coverage validator.