Commit Graph

53 Commits

Author SHA1 Message Date
shitratgit[bot] 80639a382a fix: bound flowing capture and retire old memory surfaces 2026-08-25 07:22:16 +00:00
shitratgit[bot] 5cc9423eb5 fix: require explicit Inngest event keys 2026-06-26 08:05:41 -07:00
Joel Hooks 2bcb15b604 Fix Pi startup warnings by renaming capture-progress and making memory-enforcer session-safe 2026-06-05 11:48:43 -07:00
Joel Hooks 9ee695f6e7 Remove the injected non-trivial-task ack/pause reminder from session-lifecycle turn prompts 2026-03-28 11:14:32 -07:00
Joel Hooks 825972ced3 Switch the gateway context to conversation_threads for project momentum and relationship tracking 2026-03-28 09:28:23 -07:00
Joel Hooks c29c9f753e ADR-0235: Add business intelligence to gateway context — query Typesense for recent Slack messages (7d, grouped by channel) and email threads on operator interaction. Lease typesense_api_key at startup via agent-secrets. Gateway now answers 'what's important' with actual Slack conversations and email threads, not just infra metrics. 2026-03-28 08:17:41 -07:00
Joel Hooks 3f83571dee ADR-0235: Fix context gathering speed — replace joelclaw runs (15s timeout) with joelclaw status (570ms). Drop old assistant snippets from session overflow recovery in daemon.ts. Total context gather now ~600ms instead of 8s timeout. 2026-03-28 07:24:18 -07:00
Joel Hooks ba7a1a8487 ADR-0235: Add on-demand system context gathering for gateway — when operator sends a message, gather slog (recent 15 entries), OTEL stats (24h error rate), recent runs (last 5), and failed runs (24h grouped by function) in parallel via CLI calls. Injected alongside event buffer into system prompt so gateway can answer 'what's important right now' and 'summarize this week' with real data. 2026-03-27 19:56:10 -07:00
Joel Hooks 0bb263f2bd ADR-0235 cleanup: remove dead code from gateway extension — isDigestOnlyMode, logAutomationCounter, shouldInjectHeartbeat, isHeartbeatDegraded, buildQuietDigestSummary, buildSubscriptionMessage, DrainOptions interface, AUTO_MESSAGE_DIGEST_ONLY_THRESHOLD, HEARTBEAT_FULL_CHECK_MS, automatedInjectedCount, lastFullHeartbeatCheckTs. -114 lines. 2026-03-27 19:39:02 -07:00
Joel Hooks 00775a73e7 ADR-0235: Switch gateway to demand-driven events — buffer system events silently in Redis context buffer, only inject critical events (errors/failures/degraded) as LLM messages, prepend accumulated context to system prompt when operator sends a message. Removes broadcast pattern where every drain cycle forced an LLM response. Context buffer: max 50 events, 24h TTL, grouped by type, flushed on operator interaction. 2026-03-27 19:26:53 -07:00
Joel Hooks 9f8162012e Clarify the prompt-layer hierarchy, route system-session operator updates through gateway notify, and generate session-local handles in session-lifecycle 2026-03-09 19:19:28 -07:00
Joel Hooks 1fa6d7381b Scope gateway boot memory recall to gateway-specific queries and drop procedural transcript sludge from hidden session injections 2026-03-09 16:23:19 -07:00
Joel Hooks a47c6184aa Scope gateway context refresh to real conversational topics so automated digests cannot poison the live session with unrelated memory 2026-03-09 16:14:54 -07:00
Joel Hooks f559588ea8 Upgrade live Codex policy to gpt-5.4, add a Restate PRD trigger, and bridge Restate to host agent execution via system-bus internal endpoints
Replace current 5.3 model rules/defaults with gpt-5.4 across AGENTS, skills,
gateway fallback docs/config, system-bus model constants, inference-router,
pi config, and Langfuse normalization.

Add packages/restate/src/trigger-prd.ts to compile markdown PRDs into a DAG
using pi with openai-codex/gpt-5.4, then submit Restate runs whose story nodes
dispatch host agents with a mandatory joelclaw mail contract.

Add host-only internal endpoints in packages/system-bus/src/serve.ts for:
- /internal/agent-dispatch
- /internal/agent-result/:id
- /internal/agent-await/:id

Allow per-node Restate handler timeouts so long-running PRD stories can wait on
agent completion without faking success.
2026-03-06 08:48:51 -08:00
Joel Hooks 59d69f659c Could you route subscription.updated events as dedicated feed update messages outside digest-only suppression and document the behavior? 2026-03-05 21:07:24 -08:00
Joel Hooks 0035f6fd32 fix(session-lifecycle): pipe emitEvent payload via stdin to avoid E2BIG on compaction
emitEvent passes the full serialized message transcript as a curl -d argument.
Long sessions produce multi-MB payloads that exceed macOS ~256KB argv limit,
causing 'spawn E2BIG' during auto-compaction.

Switch from -d <payload> to -d @- with stdin pipe. Same curl behavior,
no argument size limit.
2026-03-05 13:04:45 -08:00
Joel Hooks 751ff2709a Implement ADR-0211 by adding gateway behavior CLI controls, passive directive capture+prompt injection, daily advisory review, and docs/tests 2026-03-04 17:57:03 -08:00
Joel Hooks 2d57763ccb feat(gateway): ADR-0209 V3+V4 — thread fade lifecycle + per-turn injection
V3: Thread fade lifecycle with memory archival
- runFadeCycle() checks every 5min (debounced in turn_end hook)
- Threads older than 72h get archived via joelclaw memory write
- OTEL emitted for each archival (thread.archived event)
- readThreadSnapshot() helper reads daemon-persisted state

V4: Budget-efficient per-turn thread injection
- Daemon injects thread index (formatThreadIndexForPrompt) into
  every prompt — active threads show full summary, cool show label only
- Current thread tag shows label + summary + message count
- No extension-level injection (avoids context accumulation from
  hidden sendMessage calls on every turn)

Combined with V1 (classification + bidirectional reply-to) and V2
(compaction survival), the full ADR-0209 is now wired:
- Classify → Tag → Inject → Reply → Persist → Fade → Archive

Verify: restart gateway, observe thread lifecycle over 72h+,
check memory observations for archived threads.
2026-03-04 15:39:31 -08:00
Joel Hooks ad8c21c062 feat(gateway): ADR-0209 V2 — thread compaction survival via snapshot
Daemon persists thread snapshot to ~/.joelclaw/state/thread-snapshot.json
after each classification (haiku, reply-to, or fallback). Gateway
extension reads snapshot on session_compact and injects active/warm
threads into recovery context with emoji lifecycle, labels, age, and
message counts.

Thread state now survives compaction cycles. On recovery, the model
sees which threads were active and can continue them coherently.

Snapshot is best-effort (fire-and-forget write, silent catch on read).
Thread anchors are NOT persisted across gateway restarts — that would
need Redis storage (V3).

Verify: restart gateway, have multi-topic conversation, trigger
compaction, verify threads appear in recovery injection.
2026-03-04 15:19:01 -08:00
Joel Hooks dcda1bc2a7 fix(extensions): add 60s cooldown guard to prevent double-compaction cascade
Root cause: pi.sendMessage() inside session_compact handlers queues messages
that trigger agent.continue() → model response → _checkCompaction() → second
compaction. The compaction summary (~16K) + system prompt (~35K) + kept messages
(~20K) already consumes 36-55% of context window, so recovery pointer injection
pushes past threshold again.

Fix: Track lastCompactionTs in both session-lifecycle and gateway extensions.
If session_compact fires within 60s of the previous compaction, skip recovery
pointer injection entirely. First compaction gets full pointers; cascading
second is a no-op.

OTEL events added for tuning:
- compaction.before: contextPercent, contextTokens, contextLimit, timeSinceLastCompactionMs
- compaction.inject: contentChars, estimatedTokens (enriched)
- compaction.inject.skipped: reason=rapid-recompaction
- gateway.compaction.inject: contentChars, estimatedTokens (enriched)
- gateway.compaction.inject.skipped: reason=rapid-recompaction

To verify: joelclaw otel search "compaction.inject.skipped" --hours 24
To tune: adjust COMPACTION_COOLDOWN_MS (currently 60s) or GW_COMPACTION_COOLDOWN_MS

ADR-0203 updated with full root cause trace through pi-mono source.
2026-03-04 11:42:05 -08:00
Joel Hooks 8ac56f8b9f fix(gateway): add missing spawn + emitGatewayOtel for ADR-0204 Changes 2,5
Gateway periodic context refresh and compaction recovery were dead code —
spawn (child_process) was used by gwRunRecall but never imported, and
emitGatewayOtel was called but never defined/imported.

Added spawn import and inline emitGatewayOtel helper that shells to
joelclaw otel (same pattern as memory-enforcer) to avoid depending on
@joelclaw/telemetry resolution in pi extension runtime.
2026-03-04 10:05:19 -08:00
Joel Hooks c687ad0dd0 fix(memory-enforcer): move recallInjected/knowledgeInjected to module scope
The once-per-session injection guards were declared inside memoryEnforcer()
closure but referenced by seedRecall() and seedSystemKnowledge() at module
level. Bun transpiles without type-checking so it compiled, but threw
ReferenceError at runtime — silently discarding every recall result.

Move to module scope, keep reset in session_start handler.

ADR-0204 Change 1 completion.
2026-03-04 10:03:55 -08:00
Joel Hooks 0123bfa19b fix(memory-enforcer): inject recall + knowledge ONCE per session, not every turn
seedSystemKnowledge runs on before_agent_start which fires EVERY turn.
Without a guard, each turn added a new hidden sendMessage to context.
Over N turns this accumulated ~500*N tokens of duplicate injections,
causing compaction cascades (compact → first response → compact again).

Fix: recallInjected and knowledgeInjected flags, reset on session_start.
Each injection fires at most once per session lifecycle. After compaction,
the recovery pipeline (ADR-0203) provides context — no need to re-inject.
2026-03-04 09:59:07 -08:00
Joel Hooks f6dc956c59 feat(gateway): rolling context refresh + compaction recovery (ADR-0204)
Add three new capabilities to the gateway extension:

1. Periodic context refresh (every 30min):
   - Runs joelclaw recall with topics from recent conversation
   - Injects top 5 observations as hidden context-refresh message
   - Gateway now knows what's happening in the system over time
   - 60s check interval, 30min refresh interval, async non-blocking

2. turn_end compaction awareness:
   - Tracks recent conversation topics for targeted recall
   - Warm zone (40%): fire recall to cache relevant memories
   - Hot zone (60%): force refresh before compaction hits

3. session_compact recovery:
   - Builds pointer message from cached recall + recent topics
   - Injects as hidden gateway-recovery message (display: false)
   - Resets zone flags for next compaction cycle
   - OTEL event: gateway.compaction.inject

The gateway session is long-running (hours/days). Previously it had zero
context refresh and zero compaction recovery. Now it maintains rolling
awareness via Typesense recall and survives compaction with real context.

ADR-0204 Changes 2 + 5.
2026-03-04 09:55:13 -08:00
Joel Hooks e7c532f10f feat(session-lifecycle): project-scoped recall on first edit in new package
When the agent first edits a file in a package (system-bus, gateway, cli,
web, etc.), automatically run a targeted Typesense recall for that domain
and inject relevant memories as hidden context.

Scope detection maps file paths to recall queries:
  packages/system-bus/ → 'system-bus inngest worker functions deployment'
  packages/gateway/    → 'gateway daemon telegram redis event bridge'
  apps/web/            → 'joelclaw.com next.js web RSC content'
  pi/extensions/       → 'pi extension hooks lifecycle session'
  (etc.)

Each scope fires once per session (tracked in injectedScopes Set).
Uses existing runRecall() from ADR-0203 (lean budget, ~370ms).
Injects via pi.sendMessage({ customType: 'project-context', display: false }).

OTEL event: project.context.injected with scope, query, hitCount.

ADR-0204 Change 4.
2026-03-04 09:54:01 -08:00
Joel Hooks 86efb5f2c7 fix(memory-enforcer): actually inject recall + knowledge results into session context
seedRecall() and seedSystemKnowledge() were running Typesense queries,
emitting OTEL about the results, and DISCARDING the actual data. The
only thing memory-enforcer injected was the MEMORY_NUDGE write-pressure
prompt.

Now:
- seedRecall() parses recall output, formats top observations, injects
  via pi.sendMessage({ customType: 'memory-recall', display: false })
- seedSystemKnowledge() injects formatted knowledge hits via
  pi.sendMessage({ customType: 'system-knowledge', display: false })
- New OTEL events: memory.recall.injected, system_knowledge.injected
- Added formatRecallHits() and formatKnowledgeHits() parsers

Every session (interactive + gateway) now gets actual Typesense recall
results as hidden context. ADR-0204 Change 1.
2026-03-04 09:52:54 -08:00
Joel Hooks 1131358e94 refactor(session-lifecycle): replace regex extraction with Typesense recall
Rip out all regex-based signal extraction (DECISION_SIGNAL_PATTERNS,
FAILURE_SIGNAL_PATTERNS, matchSignalPatterns, extractDecisionSignals,
extractFailureSignals, deriveRecallQueries, extractAssistantText).

Replace with actual Typesense hybrid search via joelclaw recall CLI:

- triggerRecall() fires async recall queries (lean budget, ~370ms) in
  warm zone (40%+), caching results in recallCache
- buildCheckpoint() pulls validated queries + observation hits from
  cache, with fallback to simple task-derived query
- session_compact pointer now includes 'Related memories' section with
  real observations from Typesense, not regex scraps
- writeTaskContextToMemory() writes session task summary to memory so
  future sessions can find it via recall

The async Inngest observe pipeline still handles deep semantic extraction
from full session transcripts. This pipeline focuses on RETRIEVAL of
existing knowledge for post-compaction context, not extraction.
2026-03-04 09:19:29 -08:00
Joel Hooks db44906695 fix(session-lifecycle): pass --success true value to otel emit
The joelclaw otel emit --success flag takes an explicit true|false value,
not a bare boolean flag. Without the value, Effect CLI would misparse it.
2026-03-04 09:12:40 -08:00
Joel Hooks b61d790802 feat(session-lifecycle): implement ADR-0203 compaction recovery pipeline
Three-stage compaction recovery in session-lifecycle extension:

Stage 1 — Continuous signal extraction (turn_end, 40%+ context):
  - Regex patterns extract decisions and failures from assistant messages
  - Conservative patterns: 'decided to', 'the fix was', 'turns out',
    'doesn't work because', 'type error', etc.
  - Max 10 decisions, 5 failures, evict oldest when full

Stage 2 — Task checkpoint (turn_end, 60%+ context):
  - In-memory TaskCheckpoint built from: recent user messages (task),
    tracked file modifications, extracted decisions/failures
  - Observations flushed to durable memory via joelclaw memory write
  - OTEL events at warm (40%) and hot (60%) threshold crossings

Stage 3 — Pointer injection (session_compact):
  - Builds ~100 token recovery message from in-memory checkpoint
  - Contains: task summary, modified files, key decisions, recall queries
  - Injected as hidden sendMessage (display:false, no triggerTurn)
  - Zone flags reset for next compaction cycle

Supporting changes:
  - tool_execution_start handler tracks edit/write file paths
  - before_agent_start tracks last 3 user messages for task context
  - session_before_compact enhanced with final observation flush
  - All external interactions via joelclaw CLI (otel emit, memory write)
  - State fully in-memory (same process, no Redis needed for checkpoint)

ADR-0203: https://joelclaw.com/adr-0203
2026-03-04 09:12:06 -08:00
Joel Hooks f077044110 fix: skill-tracker use ExtensionAPI type, not PiExtensionContext
PiExtensionContext doesn't exist — the correct type is ExtensionAPI
from @mariozechner/pi-coding-agent. Extension wouldn't have loaded.
2026-03-04 08:32:46 -08:00
Joel Hooks 9a58a21e6b feat: skill-tracker extension — OTEL instrumentation for skill reads
Intercepts read() calls to SKILL.md files and emits 'skill.read' OTEL
events with skill name, path, and session source. Enables data-driven
skill pruning via:

  joelclaw otel search 'skill.read' --hours 168
  joelclaw otel stats --hours 720

30s debounce per skill to avoid noise from model re-reads.
Canonical source in pi/extensions/skill-tracker/, symlinked to
~/.pi/agent/extensions/.
2026-03-04 08:28:15 -08:00
Joel Hooks e3970038cc fix: deduplicate extensions, move memory-enforcer to repo, clean AGENTS.md
- Move memory-enforcer canonical source to pi/extensions/memory-enforcer/
  (was a loose file in ~/.pi/agent/extensions/, now git-tracked + symlinked)
- Remove duplicate memory-enforcer from pi-tools git/ (old HTTP-OTEL version)
- Remove duplicate identity-inject symlink from pi-tools git/
  (extensions/ symlink to repo is the canonical one)
- Remove MEMORY_NUDGE section from AGENTS.md (keep only in extension hook
  to avoid duplicating instructions in the system prompt)
- Update context budget analysis with specialist agent plan and
  dynamic skill retrieval assessment

Fixes: double memory-enforcer hooks, double identity-inject loading,
~320 tokens of duplicated memory instructions in AGENTS.md.
2026-03-04 08:22:25 -08:00
Joel Hooks 05eb4ea6d9 gateway: enforce context-local extension scope 2026-03-03 08:49:53 -08:00
Joel Hooks 89946e18b5 refactor(otel): unify ingest path across cli and extensions 2026-03-02 19:33:20 -08:00
Joel Hooks c46be6b713 langfuse: add alert-only session guardrails and normalize attribution 2026-03-02 10:43:09 -08:00
Joel Hooks dfe6636638 remove: inbox-watcher extension — replaced by pi-subagents
pi-subagents (npm:pi-subagents) provides child-process-based subagent
dispatch with proper result delivery via pi.sendMessage(), eliminating
the unreliable fs.watch + Inngest round-trip. Inngest agent-dispatch
remains for server-side durable dispatch (o11y-triage, vercel-notify).
2026-03-02 06:37:21 -08:00
Joel Hooks 27003e7be5 identity-inject: reload role context on session start 2026-03-01 16:38:34 -08:00
Joel Hooks 31534b920b roles: add system profile and role alias routing 2026-03-01 16:29:24 -08:00
Joel Hooks 3be890c8bf gateway: enforce role routing and rapid steering check-ins 2026-03-01 15:59:57 -08:00
Joel Hooks 0fd97aec1a feat(clawmail): add canonical mail protocol skill and prompt refs 2026-03-01 10:51:32 -08:00
Joel Hooks 2530445985 fix(session-lifecycle): fallback event key to system-bus env 2026-03-01 10:32:18 -08:00
Joel Hooks 743e143dfc fix(agent-mail): detect degraded mail search signals 2026-03-01 10:20:43 -08:00
Joel Hooks c4f2d6ac3b feat(agent-mail): add daily steering snapshot loop 2026-03-01 10:18:34 -08:00
Joel Hooks f62c0b41b3 feat(mail): add ttl renew + protocol nudge 2026-03-01 10:06:21 -08:00
Joel Hooks 9d85c8a7de feat(agent-dispatch): add readFiles flag for background agent tasks
Surfaces readFiles boolean through event schema, agent-dispatch function,
and inbox-watcher extension. Pi dispatch with readFiles throws
NonRetriableError (use codex/claude instead). vault.ts gains frontmatter
pass-through in ADR catalog type.
2026-03-01 07:03:14 -08:00
Joel Hooks e3da2827cf fix: private discoveries + revalidation secret wiring
- Add private: true frontmatter guard to upsertDiscovery (skips like draft)
- Content-sync removes private discoveries from Convex on every run
- Add revalidation_secret to agent-secrets + Talon SECRET_MAPPINGS
- Worker can now actually revalidate Next.js cache (was silently skipping)
2026-02-28 20:21:27 -08:00
Joel Hooks a7f3e2b970 enrich identity-inject OTEL metadata with totalChars, missingFiles, truncatedFiles, loadTimeMs, identityDir 2026-02-28 15:42:47 -08:00
Joel Hooks b050d7dc77 fix(identity-inject): correct pi API type, prepend identity, add ROLE.md, TOOLS truncation 2026-02-28 15:01:11 -08:00
Joel Hooks 56d7080f87 langfuse: guard optional dependency with import regression test 2026-02-28 13:45:04 -08:00
Joel Hooks fc33ecdf3c fix: harden optional langfuse module loading 2026-02-28 13:05:09 -08:00