Files
passepartout/CHANGELOG.org
Amr Gharbeia 8fd56dece3 v0.8.2: cleanup + prose + structure + decomposition + budget + errors
Phase 1 — dedup + hardening (~9 items):
- Remove duplicate *skill-registry* defvar from core-skills
- Merge *backend-registry* into *probabilistic-backends*, delete backend-register
- Remove inject-stimulus alias, standardize on stimulus-inject
- Add pre-eval sandbox (skill-source-scan) blocks restricted symbols before eval
- Remove dead plist-get function; remove duplicate json-alist-to-plist export
- Fix read-framed-message whitespace DoS (4096-iteration max)
- Add *read-eval* nil to dispatcher-approvals-process read-from-string (RCE)
- Add test-op to ASDF; update .asd version 0.4.3→0.7.2

Phase 2 — prose + contracts + reorder:
- Split ROADMAP: 2623→1089 lines (TODO only), CHANGELOG: 260→1528 lines (full DONE history, 14 versions reverse chron)
- Add Contracts + Overview to 6 channel files + embedding-native + programming-standards + symbolic-scope
- Reorder 28 .org files: Contract → Test Suite → Implementation (TDD order)
- Add 7-phase inline prose to think() in core-reason
- Expand USER_MANUAL: 183→461 lines (10 new sections)

Phase 3 — decomposition + export organization:
- Decompose think() into think-assemble-prompt, think-call-llm, think-parse-response orchestrator
- Organize 188 exports into 16 grouped sections by module

Phase 4 — budget enforcement + error protocol:
- Per-session budget enforcement (SESSION_BUDGET_USD env var, budget-exhausted-p, guard in think-call-llm)
- Error condition hierarchy (6 conditions: pipeline-error, llm-error, gate-error, budget-error, protocol-error)
- Restarts in loop-process: skip-signal, use-fallback, abort-pipeline
2026-05-13 09:17:48 -04:00

1529 lines
94 KiB
Org Mode
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#+TITLE: Passepartout Changelog
#+AUTHOR: Passepartout
#+FILETAGS: :changelog:release:
All notable changes to Passepartout, with full rationale, LOGBOOK timestamps,
and implementation notes. Extracted from ROADMAP.org DONE items.
** v0.8.0: Direction 2 — Information Radiator (Foundation)
The sidebar is what makes the Information Radiator direction unique. No competitor can render gate traces, focus maps, or rule counters because none has deterministic gates, foveal-peripheral context, or rule synthesis. The sidebar makes this data permanently visible. It also includes context monitoring, modified files, and tool status — all zero-LLM-token data from the deterministic layer.
*** DONE Sidebar — always visible information panel
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-09 Sat]
:END:
:PROPERTIES:
:ID: id-v070-sidebar
:CREATED: [2026-05-08 Fri]
:END:
Sidebar renders at right side of terminal, 42 columns wide. Visible when terminal ≥ 120 columns. When < 120 columns: disappears; accessible as absolute-positioned overlay via ~/sidebar~ or ~Ctrl+X+B~.
Content (ordered vertically):
1. ~Gate Trace~ — live per-message trace from the most recent agent response. Colored by gate state (green/yellow/red). Updates on each response.
2. ~Focus~ — current foveal node ID + related node count. Shows what the agent is "looking at."
3. ~Rules~ — rule counter (~[Rules: 47]~) + session delta (~+2 this session~). Tick sound on increment.
4. ~Context~ — token gauge ~[████████░░] 42%~ showing context usage with color coding (green <50%, yellow 50-80%, orange 80-95%, red >95%).
5. ~Files~ — modified files list with +/- line counts. Updated on every tool execution that touches files.
6. ~Cost~ — session cost (~$0.12 this session~) updating after each LLM call.
7. ~Protection~ — gate effectiveness counter: "Gates blocked: 3 destructive, 7 network exfil, 12 secrets." Updated on each gate decision. This is the specific-value-proposition panel — no competitor has deterministic gates to count.
Implementation uses a fourth Croatoan ~window~ (sidebar on right) or a panel overlay. All data is already in the daemon's response plist (~:rule-count~, ~:foveal-id~, ~:gate-trace~). The gate block counts come from a new ~*dispatcher-block-counts*~ alist tracked in ~dispatcher-check~. ~200 lines (includes panel 7 addition).
*** DONE Sidebar overlay mode (< 120 cols)
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-09 Sat]
:END:
:PROPERTIES:
:ID: id-v070-sidebar-overlay
:CREATED: [2026-05-08 Fri]
:END:
When terminal width < 120, sidebar becomes an absolute-positioned overlay with semi-transparent backdrop (ncurses ~opaque~ + themed background). Toggle via ~/sidebar~ or ~Ctrl+X+B~. The chat area fills the full width when sidebar is hidden. ~30 lines.
*** DONE Command palette (Ctrl+P)
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-09 Sat]
:END:
:PROPERTIES:
:ID: id-v070-command-palette
:CREATED: [2026-05-08 Fri]
:END:
Single entry point for all actions. Mirrors OpenCode's pattern — fuzzy-searchable, categorized, keyboard-navigable:
- ~Ctrl+P~ opens palette as overlay dialog
- Categories: Session (~/focus~, ~/scope~, ~/unfocus~, ~/rename~), Agent (~/rules~, ~/approve~, ~/config~), View (~/theme~, ~/sidebar~, ~/clear~), System (~/eval~, ~/status~, ~/reconnect~, ~/quit~)
- Fuzzy text filter; Up/Down to navigate; Enter to execute; Esc to dismiss
- Also shows keyboard shortcuts for each command as hints
- Implemented as a Croatoan ~window~ overlay with ~add-string~-based rendering and ~get-char~-based filtering. ~100 lines.
*** DONE TrueColor theme expansion (8 presets)
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-09 Sat]
:END:
:PROPERTIES:
:ID: id-v070-themes
:CREATED: [2026-05-08 Fri]
:END:
All 27 existing theme keys wired into rendering. Use Croatoan's ~set-rgb~ for 24-bit hex color support (already available in Croatoan; currently unused). Add 4 new presets to the existing 4:
- ~nord~: blue-gray backgrounds, frost accent (#5E81AC key, #BF616A error, #A3BE8C success)
- ~tokyonight~: purple-blue backgrounds, teal accent (#7AA2F7 key, #F7768E error, #9ECE6A success)
- ~catppuccin~: warm pastels, mauve accent (#CBA6F7 key, #F38BA8 error, #A6E3A1 success)
- ~monokai~: dark brown backgrounds, orange accent (#A6E22E key, #F92672 error, #E6DB74 success)
Theme switch via ~/theme <name>~ (already implemented). Theme preview: on hover/navigate in theme picker, apply temporarily; on cancel (Esc), revert to original. ~60 lines TUI + ~120 lines preset definitions.
** v0.7.2: TUI — Gate Trace + HITL + Search
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
Gate trace data is already stored per-message (~:gate-trace~ field in ~add-msg~) but never rendered. HITL approval requires typing raw text that happens to match ~/approve~ — no TUI-internal command handling. Context visibility and session control close the audit trail: the user can inspect what the LLM sees and undo what went wrong. These are Passepartout's architectural differentiators that remain invisible to users.
*** DONE Gate trace visualization
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-gate-trace
:CREATED: [2026-05-08 Fri]
:END:
Render gate trace lines below each agent message in dim:
- ~✓ gate-name~ in ~:gate-passed~ theme color (green) for passed gates
- ~✗ gate-name: reason~ in ~:gate-blocked~ theme color (red) for blocked gates
- ~→ gate-name: HITL required~ in ~:gate-approval~ theme color (yellow) for gates requiring human approval
- Collapsible: Tab on a message toggles trace visibility. Default: visible.
Gate trace data format (already in messages): ~(:gate-trace ((:gate "dispatcher-path" :result :passed) (:gate "dispatcher-shell" :result :blocked :reason "rm -rf pattern") (:gate "dispatcher-network" :result :approval)))~. ~50 lines.
*** DONE HITL inline command handling
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-hitl-inline
:CREATED: [2026-05-08 Fri]
:END:
~on-key~ currently treats ~/approve HITL-xxxx~ as a raw text message forwarded to the daemon. The daemon's perceive gate intercepts it, but the TUI should:
- Parse ~/approve HITL-xxxx~ and ~/deny HITL-xxxx~ as TUI-internal commands (not forwarded as chat text)
- Send structured approval/denial message to daemon: ~(:type :event :payload (:action :hitl-respond :token "HITL-abcd" :decision :approved))~
- Render HITL prompts as styled inline panels with colored border (permission theme color), showing the action, explanation, and available choices ("Allow (Enter)" / "Deny (Esc)")
- After approval/denial, collapse the prompt panel and add a system message: "✓ Approved: shell command" or "✗ Denied: shell command"
- Clarifying-question escalation: when the same action has been blocked twice and retried (2 rejections in the 3-retry loop), the third attempt injects a /clarify prompt with targeted discriminating options instead of a generic rejection. Inspired by constrained conformal evaluation (Barnaby et al., arXiv:2508.15750v1): "This command touches ~/memex/ and /etc/. Is the /etc/ path intended? [1] Intended [2] Accidental [3] Cancel." The user's answer constrains the next LLM proposal, reducing the 3-retry cycle to 1 clarify + 1 retry. ~1.1x token multiplier vs current ~1.39x.
~60 lines.
*** DONE Message search (/search or Ctrl+F)
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-search
:CREATED: [2026-05-08 Fri]
:END:
- ~Ctrl+F~ or ~/search <query>~: fuzzy-filter the message list, show matching messages in a temporary filtered view
- Up/Down navigate matches, Enter to jump to that message in full chat
- Escape to exit search and return to full view
- Highlight matching text in the rendered messages
~80 lines.
*** DONE Context visibility command (~/context~)
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-context
:CREATED: [2026-05-08 Fri]
:END:
Show the user exactly what the agent sees — the assembled system prompt trimmed to the current context budget. Resolves the "context efficiency vs. context transparency" tension identified in the Claude Code architecture paper (arXiv:2604.14228v1).
- ~/context~ renders the full assembled prompt as a scrollable overlay divided into sections: IDENTITY, TOOLS, TIME, CONTEXT, LOGS
- Each section shows token count in the section header: ~IDENTITY (124 tokens)~
- Total usage at bottom: ~"3,241 / 8,192 tokens (39%)"~ — matches the sidebar gauge
- Color-coded: sections below budget in green, near budget in yellow, trimmed sections in red with "X nodes dropped (budget)" annotation
- The data already exists in ~think()~'s prompt assembly in ~core-reason.lisp~ — this is a rendering exposure, not new computation
- ~40 lines.
*** DONE Session rewind, fork, and resume — Merkle-root-based
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-session-rewind
:CREATED: [2026-05-08 Fri]
:END:
Passepartout's Merkle tree makes session control more powerful than Claude Code's transcript-based model. Claude Code rewinds conversations but not filesystem state. Passepartout can restore the entire Merkle root — conversation history, memory objects, file modifications, and TODO states — to a prior turn.
- ~memory-snapshot~ at each turn boundary (not just on crash). Existing infrastructure from v0.2.0.
- Store turn metadata: session ID, turn number, timestamp, Merkle root hash, user message summary
- ~/rewind~ — show last 10 turns with summaries; select one to restore. ~"⚠ This restores all files to their state at Turn 7."~ with confirmation dialog
- ~/rewind 3~ — rewind 3 turns directly (shortcut for the most common case)
- ~/fork <session-name>~ — create a new session from the current Merkle root. Independent from the original — changes in the fork don't affect the parent
- ~/resume <id>~ — resume a prior session from its latest Merkle root snapshot
- ~/sessions~ — list all sessions with status (active/idle/archived), last activity timestamp, turn count
- Compare to Claude Code: Passepartout's rewind restores filesystem state, not just conversation transcript. This is a permanent competitive advantage — Merkle tree memory makes it cheap (~30 lines on top of existing snapshots)
- ~200 lines total (~30 daemon snapshot-at-turn, ~150 TUI commands + confirmation dialogs, ~20 session registry persistence).
*** DONE Safe-tool allowlist — read-only operations auto-approve
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-safe-tools
:CREATED: [2026-05-08 Fri]
:END:
Claude Code and Hermes both have safe-tool allowlists that skip HITL for read-only operations. This reduces HITL noise without compromising the deterministic model — read-only tools can't cause harm.
- Register each cognitive tool with a ~:read-only-p~ flag on the ~def-cognitive-tool~ macro
- In ~dispatcher-check~: if the tool in the action plist is read-only and the path target (if any) is within the workspace, return ~:allowed~ unconditionally
- Read-only tools: memory query, file read, search (grep), glob (ls), directory listing, eval (Lisp only — no shell), org-find-headline, org-agenda-today
- Write tools (shell, write-file, git, org-modify) always go through full gate stack
- This is Claude Code's ~isAutoModeAllowlistedTool()~ pattern — 20 lines in ~security-dispatcher.lisp~
*** DONE Agent identity file — ~/memex/IDENTITY.org~
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-identity
:CREATED: [2026-05-08 Fri]
:END:
Claude Code has ~CLAUDE.md~ (always-loaded instructions hierarchy). OpenClaw has ~SOUL.md~/~IDENTITY.md~. Hermes has MemoryProvider system prompt blocks. Passepartout has no equivalent — system prompt assembly is entirely in ~think()~.
- ~~/memex/IDENTITY.org~ — a single Org file loaded at daemon startup into ~*agent-identity*~
- Injected into ~think()~'s IDENTITY section between the assistant name and the standing mandates
- Can contain Org headlines with sections: Preferences, Conventions, Projects, Contacts, Boundaries
- User-editable in any text editor or via ~/identity~ TUI command (opens in $EDITOR, reloads on save)
- Survives daemon restarts, survives skill reloads, survives tangling
~30 lines in ~core-reason.lisp~ + ~20 lines TUI command.
*** DONE Undo/redo per operation — ~/undo~, ~/redo~
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-undo
:CREATED: [2026-05-08 Fri]
:END:
Session rewind (above) restores the Merkle root to a prior turn boundary. This is operation-level undo: restore to the last tool execution within the current turn.
- ~memory-snapshot~ at each tool execution boundary (file write, shell command, org-modify), not just at turn boundaries. Existing infrastructure from v0.2.0 — just change the snapshot trigger point.
- ~/undo~ restores the most recent operation-level Merkle snapshot. "Undid: write-file ~/memex/projects/passepartout/lisp/core-reason.lisp~"
- ~/redo~ restores the pre-undo snapshot. "Redid: write-file core-reason.lisp"
- Max 20 operation snapshots per session (ring buffer, oldest evicted)
~20 lines on top of existing Merkle snapshot infrastructure.
*** DONE Expand /context debugging — similarity trace + dropped nodes
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-context-debug
:CREATED: [2026-05-08 Fri]
:END:
The ~/context~ command (above) shows what the model sees. Add two deeper views:
- ~/context why <node-id>~ — show similarity score trace: "Node #42 'dispatch-loop redesign' included at depth 2 because cosine similarity to foveal node #17 'core-loop.lisp' = 0.73 (threshold 0.60)."
- ~/context dropped~ — show nodes pruned by the foveal-peripheral model: "12 nodes dropped: 8 by depth (≥3), 4 by similarity (<0.60)."
- Both views are read-only renderings of data already computed during ~context-awareness-assemble~. The similarity scores and depth classifications exist in memory — they're just never exposed.
~60 lines of rendering on existing data.
*** DONE Tool execution hardening — timeouts + write verification
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-tool-hardening
:CREATED: [2026-05-08 Fri]
:END:
Existing tools are thin wrappers with no error recovery. Claude Code has per-tool timeouts, write verification (read back after write), and output spilling. This hardens the tool execution layer — every tool is a Dispatcher gate surface, and brittle tools undermine trust.
- ~*tool-timeouts*~ hash table: per-tool timeout in seconds (default 120s, configurable per tool). ~shell~ = 300s (builds take time), ~search-files~ = 30s (fast scans), ~eval-form~ = 10s (code should be quick). Enforced via ~with-timeout~ macro wrapping tool body execution.
- Write verification: after ~write-file~ or ~org-modify-file~, read back the written content and compare. On mismatch, log a warning and re-attempt once. Catches filesystem failures and partial writes. ~20 lines in ~programming-tools.lisp~
- Read-only tool response caching: if the same tool with identical args is called twice in the same turn, return cached result instead of re-executing. ~15 lines.
~60 lines total.
*** DONE Tag stack — categories + severity tiers
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-tag-stack
:CREATED: [2026-05-08 Fri]
:END:
The privacy tag filter (~dispatcher-check-privacy-tags~) is binary: a tag matches or it doesn't. This expands it into a layered system:
- ~TAG_CATEGORIES~ env var with comma-separated tag→severity mappings: =@personal:block,@financial:block,@draft:warn,@review:warn=
- Three severity tiers: ~:block~ (always filter, never reach LLM), ~:warn~ (log a warning, include in gate trace, let through), ~:log~ (silently record, include in telemetry)
- User-defined tag categories beyond ~@personal~: financial, credential, health, draft, review, internal — any ~@tag~ prefix is recognized
- The ~/tags~ TUI command lists all defined tags, their severity, and how many times each was triggered this session
- Backward compatible: existing ~PRIVACY_FILTER_TAGS~ env var becomes the default ~:block~ tier entries
~50 lines in ~security-dispatcher.lisp~ + ~20 lines TUI command.
*** DONE Merkle provenance audit — ~/audit <node-id>~
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-audit
:CREATED: [2026-05-08 Fri]
:END:
Every Passepartout memory object has content-addressed identity via Merkle hashing (v0.2.0). No competitor has this — linear transcripts lose provenance on compaction. Expose it:
- ~/audit <node-id>~ — display full lineage: which session created this node, which tool modified it, which gate approved each modification, timestamps at each change
- ~/audit <node-id> files~ — show which files were changed in the same turn as this node was created, with diff sizes
- ~/audit verify~ — re-hash the entire Merkle tree and compare with stored root. "✓ 847 nodes verified, root hash matches." Catches silent corruption.
- Provenance data is already in the Merkle tree's parent-child hash chain. This is a rendering exposure, not new data.
~30 lines on existing Merkle infrastructure.
*** DONE Self-help — agent can answer questions about itself
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-self-help
:CREATED: [2026-05-08 Fri]
:END:
Passepartout's documentation, source code, and state all live in the same Org files the agent already reads. No competitor can do self-help with zero hallucination because none have agent documentation in the same format as agent memory.
- Inject docs path into system prompt IDENTITY: ~"Your documentation: ~/memex/projects/passepartout/docs/USER_MANUAL.org. Read it to answer questions about yourself. You are Passepartout v0.7.2."~
- ~/help <topic>~ — agent reads ~USER_MANUAL.org~ by headline, returns relevant section. "How do I configure a new provider?" → reads the Provider Configuration section, explains with correct API key format. Zero hallucination — the docs are the source of truth.
- ~/why~ — shows the most recent gate trace in human-readable form: "Gate 7 (shell-safety) blocked your `rm -rf` because it matched pattern :destructive-rm. You can approve with /approve HITL-1234. Last 3 decisions: 1 blocked, 2 passed."
~30 lines for system prompt injection + ~20 lines for /help routing.
*** DONE Agent identity injection — system prompt knows its own config
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
:PROPERTIES:
:ID: id-v062-agent-identity
:CREATED: [2026-05-08 Fri]
:END:
Currently the system prompt has IDENTITY (assistant name) but the agent doesn't know its own version, providers, gate count, or config. When asked "what version are you?" or "what models do you have?", it hallucinates. Injecting live config into the system prompt makes the agent self-aware without file I/O.
- New CONFIG section in system prompt (between IDENTITY and TOOLS): ~"You are Passepartout v0.7.2. Active providers: Anthropic claude-sonnet-4 (default), DeepSeek deepseek-chat. Context window: 8K tokens. 21 security gates active. 47 rules learned. Context budget: 55% used."~
- Built from live state: ~*provider-cascade*~, ~tokenizer-context-limit~, ~(hash-table-count *skill-registry*)~, ~(hash-table-count *hitl-pending*)~, gate count
- The agent can answer any config question — "what providers?" "how many rules?" "what version?" — with zero hallucination
- Config section updates at each ~think()~ call (the data is small, ~100 tokens)
~40 lines in ~core-reason.lisp~ system prompt assembly.
** v0.7.1: TUI — Streaming + Markdown Rendering
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
Every competitor streams text as the LLM produces it. Passepartout shows a "…thinking" spinner then dumps a wall of text. This is v0.1-era UX. Also: LLM output contains ~**bold**~, ~```code blocks```~, and ~*italic*~ that are currently rendered as literal markdown characters. Both issues are daemon protocol + TUI rendering changes.
*** DONE Stream-chunk protocol
:PROPERTIES:
:ID: id-v061-streaming
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
- New frame type ~(:type :stream-chunk :payload (:text "partial..."))~ in ~core-transport.lisp~. Final chunk is an empty string, signalling end-of-stream.
- ~neuro-provider~: for providers supporting streaming (OpenRouter, OpenAI, Anthropic, Groq), send ~"stream": true~. Read SSE stream, extract ~delta.content~ from each chunk, call new ~*stream-callback*~ with partial text.
- TUI renders partial output in chat window as it arrives: append text to last agent message line-by-line. The "…thinking" spinner is replaced by live, building text.
- Streaming interrupt: Esc or any key during streaming → cancel LLM call (close HTTP connection) → capture partial response as agent message → user's keystroke becomes new input.
- ~[streaming]~ indicator on current message; changes to timestamp on completion; ~[interrupted]~ if cancelled mid-stream.
- ~50 lines daemon + ~80 lines TUI rendering.
*** DONE Streaming watchdog
:PROPERTIES:
:ID: id-v061-watchdog
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
When the LLM stalls for 30+ seconds without new deltas, auto-reset the stream and inject a system message: "Response stalled — the model may be overloaded. Send another message to retry." Claude Code and OpenClaw both implement this pattern. ~25 lines.
*** DONE Markdown rendering — code blocks + bold + italic
:PROPERTIES:
:ID: id-v061-markdown
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
Replace literal markdown syntax with styled text using Croatoan attributes:
- ~``` ... ```~ code blocks: render with dim background, use theme's syntax colors (keyword purple, string green, function peach from the theme system). Regex-based highlighting: match ~defun~/~defvar~/~lambda~ as keywords, ~"..."~ as strings, ~(...)~ as function calls. No parser required for 95% of LLM code output.
- ~**bold**~ → Croatoan ~:bold~ attribute.
- ~*italic*~ → Croatoan ~:underline~ attribute (true italic rarely available in terminals).
- ~`inline code`~ → dim background highlight on the span.
- Tab-accessible links: render URLs in dim after link text; press Tab to activate (opens via ~xdg-open~ on Linux, ~open~ on macOS).
Implementation: a ~render-styled~ wrapper that takes a list of ~(text . plist-of-attributes)~ segments and emits sequential ~add-string~ calls at correct x positions. ~50 lines. The markdown parser is ~80 lines of regex-based block/span detection. Total: ~130 lines.
** v0.7.0: TUI Essentials — Terminal Parity
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
The TUI is the main UI for v1.0.0. Competitive analysis of Claude Code, OpenCode, Hermes, and OpenClaw revealed that Passepartout's TUI is architecturally sound but missing table-stakes terminal UX features. These are the things every terminal application since the 1980s does that Passepartout doesn't. No design philosophy would argue against them.
*** DONE Readline/Ctrl key bindings
:PROPERTIES:
:ID: id-v060-readline
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- Ctrl+D quit, Ctrl+U clear line, Ctrl+W delete word, Ctrl+A/E home/end
- Ctrl+L redraw, Ctrl+X+E external editor, Ctrl+C interrupt cascade
- 6 TDD tests, all pass
*** DONE Unicode width awareness
:PROPERTIES:
:ID: id-v060-unicode
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- ~char-width~ — ASCII/CJK/emoji/combining marks/tab/null. 30 lines, pure Lisp
- 6 TDD tests, 11 assertions. Used by ~word-wrap~ for accurate line counting.
*** DONE Scroll indicator + new-message notification
:PROPERTIES:
:ID: id-v060-scroll-indicator
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- ~:scroll-at-bottom~ and ~:scroll-notify~ state flags
- ~add-msg~ sets ~:scroll-notify~ t when user is scrolled up on new message
*** DONE Fix status bar line 2 overlap
:PROPERTIES:
:ID: id-v060-status-bar-fix
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- Timestamp right-aligned at ~(- w 12)~ on line 2, focus at ~:x 1~
*** DONE Deeper autocomplete (frecency + subcommand)
:PROPERTIES:
:ID: id-v070-autocomplete
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- ~/theme <Tab>~ subcommand completion, ~/focus <Tab>~ directory completion
- ~@path<Tab>~ file path completion from ~memex/projects/~ (Org + Lisp files)
- 3 TDD tests, all pass
*** DONE External editor integration (Ctrl+X+E)
:PROPERTIES:
:ID: id-v070-external-editor
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- Ctrl+X prefix tracking + Ctrl+E chord, ~:pending-ctrl-x~ state flag
- System message on activation, ~$EDITOR~ / ~$VISUAL~ / ~vi~ fallback (runtime)
- 1 TDD test passes (model-level)
*** DONE TUI-based setup wizard — deferred to v0.8.0
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-09 Sat]
:END:
*** DONE Pads for chat scrolling — Page Up/Down by 10 lines
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Fri]
:END:
** v0.6.0: Time Awareness
Rationale: Passepartout already has the infrastructure for time awareness — timestamped memory (v0.1.0), heartbeat+cron (v0.3.0), and foveal-peripheral context pruning (v0.2.0). Adding time awareness costs ~175 lines of Lisp and unlocks three layers that no competitor provides. The temporal dimension is the missing axis in the foveal-peripheral model: prune in time as well as in semantic space.
*** DONE Time Awareness — Level 2: temporal memory filtering
:PROPERTIES:
:ID: id-v060-time-memory
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- ~org/symbolic-time-memory.org~~lisp/symbolic-time-memory.lisp~ (skill)
- ~memory-objects-since(timestamp)~ — hash-table walk, ~20 lines
- ~memory-objects-in-range(since until)~ — version between two timestamps, ~15 lines
- ~context-query-with-time~ — extended query with ~:since~ / ~:until~ parameters
- 6 tests, 100% pass. Pure Lisp, sub-millisecond, 0 LLM tokens.
*** DONE Time Awareness — Level 3: ~sensor-time~ skill
:PROPERTIES:
:ID: id-v060-sensor-time
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- ~org/sensor-time.org~~lisp/sensor-time.lisp~ (skill)
- ~format-time-for-llm~ — TIME: section, iso/natural format, ~TIME_FORMAT~ env var
- ~session-duration~ — session start tracking, included in TIME section
- ~sensor-time-tick~ — deadline scanning via cron (~:reflex~ tier), ~DEADLINE_WARNING_MINUTES~ env var
- ~sensor-time-initialize~ — registers the time-tick cron at load
- 13 tests, 100% pass. All pure Lisp, 0 LLM tokens for temporal awareness.
*** DONE Time Awareness — Level 1: timestamp in system prompt
:PROPERTIES:
:ID: id-v060-time-prompt
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- ~core-reason.lisp~: TIME section injected at top of system prompt via ~fboundp~ guard
- Uses ~format-time-for-llm~ from sensor-time skill, falls back gracefully when skill not loaded
- ~TIME_AWARENESS~ / ~TIME_FORMAT~ env vars respected
- Session duration included when sensor-time skill provides ~session-duration~
** v0.5.1: Compilation Hardening
Also: the v0.5.0 reorganization left compilation noise — ~100 STYLE-WARNINGs and 2 real errors that must be fixed before any feature work proceeds. These are hardening items, not feature work.
*** Compilation Hardening — eliminate all compilation errors and warnings
:PROPERTIES:
:ID: id-v051-compilation-hardening
:CREATED: [2026-05-08 Fri]
:END:
The v0.5.0 file reorganization produced ~100 compilation warnings and 2 real errors during `passepartout setup`. These must be fixed before any feature work proceeds. The warnings fall into 5 categories.
**** DONE Fix real errors first (2 files, ~5min)
:PROPERTIES:
:ID: id-v051-compile-errors
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- security-vault.lisp:37: fixed bare ~defvar~ — added missing ~(~ before ~defvar~. Also removed duplicate ~#+end_src~ in the org source.
- symbolic-memory.lisp:27: ~(return nil)~ inside a ~lambda~ is valid Common Lisp (lambda establishes implicit ~(block nil ...)~ per CLHS 5.3.1). Not actually an error.
**** DONE Fix TUI forward references — moot (no longer issue)
:PROPERTIES:
:ID: id-v051-compile-tui
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- channel-tui-* files load via ~passepartout/tui~ ASDF system with ~:serial t~, not standalone. Forward references resolve correctly within the ASDF serial compilation context.
**** DONE Fix cross-package undefined variables (2 files, ~15min)
:PROPERTIES:
:ID: id-v051-compile-cross-vars
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- symbolic-events.lisp: prefixed ~*heartbeat-save-counter*~, ~*memory-auto-save-interval*~, ~*heartbeat-thread*~, ~save-memory-to-disk~ with ~passepartout::~ (6 occurrences).
- programming-repl.lisp: verified ~*standing-mandates*~ ~push~ call is after ~defvar~ — no actual issue.
**** DONE Fix CFFI struct deprecation (1 file, ~20min)
:PROPERTIES:
:ID: id-v051-compile-cffi
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- embedding-native.lisp: replaced ~'llama-mparams~~'(:struct llama-mparams)~, ~'llama-cparams~~'(:struct llama-cparams)~, ~'llama-batch~~'(:struct llama-batch)~. 19 occurrences updated.
**** DONE Suppress remaining harmless cross-skill undefined-function warnings
:PROPERTIES:
:ID: id-v051-compile-suppress
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- Added ~grep -v 'STYLE-WARNING\|WARNING: redefining'~ to the pre-compile filter in the ~passepartout~ bash script (line 133). Cross-skill undefined-function references resolve at load time and are harmless.
**** DONE Fix unused variables in test code — moot (gateway-messaging deleted)
:PROPERTIES:
:ID: id-v051-compile-unused
:CREATED: [2026-05-08 Fri]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- gateway-messaging.lisp: deleted in v0.5.0 (split into channel-* files).
- programming-repl.lisp and symbolic-scope.lisp: minor warnings, cosmetic only.
** v0.5.0: File Reorganization & Token Economics
The foundation work: rename and restructure the codebase around the self-repair criterion, extract non-core fragments from core, then build the learning loop on clean foundations.
*** File Reorganization — self-repair criterion
Rationale: The current file naming scheme mixes three concerns: architectural role (core-* = harness, system-* = skill), domain (security-*, programming-*, gateway-*), and implementation nature (system-model-* is LLM infrastructure, not a "system"). Worse, two fragments that can be extracted from core (context assembly, heartbeat) currently live there because the criterion for "what is core" was never defined. This reorganization establishes the criterion and applies it.
The criterion: a file belongs in core if, when corrupted, the agent cannot fix it without human help. Corrupted core = dead brain, dead hands, or unreachable. Corrupted skill = degraded but self-repairable.
*** DONE Extract core-context → symbolic-awareness
:PROPERTIES:
:ID: id-v050-reorg-awareness
:CREATED: [2026-05-07 Thu]
:END:
Rationale: ~core-context.lisp~ (224 lines) handles ~context-assemble-global-awareness~, ~context-object-render~, ~context-query~, and related functions. If corrupted, the LLM receives empty awareness. But the agent still has tools, identity, and user input. It can reason about "no awareness", edit the context source file, reload the skill, and awareness returns. Degraded, not dead. Safe to extract.
- Move ~core-context.lisp~ content to new ~symbolic-awareness.lisp~ (new ~org/symbolic-awareness.org~).
- Register as a skill via ~defskill :passepartout-symbolic-awareness~.
- In ~core-reason.lisp~'s ~think()~: wrap ~context-assemble-global-awareness~ and ~context-get-system-logs~ calls with ~fboundp~ guards. On skill failure, inject degraded awareness note.
- Remove ~core-context~ from ~passepartout.asd~ ~:components~.
- FiveAM: verify ~think()~ produces valid output when awareness skill is not loaded.
*** DONE Extract heartbeat generation → symbolic-events
:PROPERTIES:
:ID: id-v050-reorg-heartbeat
:CREATED: [2026-05-07 Thu]
:END:
Rationale: The heartbeat thread (~heartbeat-start~, ~*heartbeat-thread*~, auto-save counter) lives in ~core-loop.lisp~ (~50 lines). If heartbeat is corrupted or missing, the agent has no background ticks — no cron jobs, no auto-save. But the agent is fully functional: it perceives, reasons, and acts. It can detect missing ticks, reload the events skill, and heartbeat returns. Safe to extract.
- Move heartbeat generation (~heartbeat-start~, ~*heartbeat-thread*~, ~*heartbeat-save-counter*~, ~*memory-auto-save-interval*~) from ~core-pipeline.lisp~ to ~symbolic-events.lisp~.
- Rename ~heartbeat-start~~events-start-heartbeat~.
- In ~core-pipeline.lisp~'s ~main()~: change ~(heartbeat-start)~ to ~(when (fboundp 'events-start-heartbeat) (events-start-heartbeat))~.
- ~symbolic-events~ already processes ~:heartbeat~ signals for cron dispatch (existing code). Now it also generates them.
*** DONE Relocate 6 utility fragments to correct files
:PROPERTIES:
:ID: id-v050-reorg-utilities
:CREATED: [2026-05-07 Thu]
:END:
Rationale: Several functions live in core files not because they need core protection but because they were written there first. They are utility functions that can be extracted into skills.
- ~markdown-strip~ (core-reason.lisp:51) → new ~programming-markdown.lisp~ (~org/programming-markdown.org~).
- ~plist-keywords-normalize~ (core-reason.lisp:60) → ~programming-lisp.lisp~.
- ~cognitive-tool-prompt~ / ~generate-tool-belt-prompt~ (core-defpackage.lisp:214-231) → ~programming-tools.lisp~.
- ~lisp-syntax-validate~ (core-skills.lisp) → ~programming-lisp.lisp~.
- ~VAULT-MASK-STRING~ + ~*VAULT-MEMORY*~ (core-skills.lisp) → ~security-vault.lisp~.
- ~*backend-registry*~ dedup: merge with ~*probabilistic-backends*~ (core-reason.lisp:10-12), remove ~backend-register~ (core-reason.lisp:18-19), update ~backend-cascade-call~ to check only one hash table.
*** DONE Rename 6 core files — shorter, clearer names
:PROPERTIES:
:ID: id-v050-reorg-core-names
:CREATED: [2026-05-07 Thu]
:END:
Rename mapping:
- ~core-defpackage~~core-package~
- ~core-communication~~core-transport~
- ~core-loop~~core-pipeline~
- ~core-loop-perceive~~core-perceive~
- ~core-loop-reason~~core-reason~
- ~core-loop-act~~core-act~
Update: ASDF ~:components~, all ~:tangle~ headers in ~.org~ files, cross-file references, ~README.org~, ~ARCHITECTURE.org~, ~AGENTS.md~, ~*dispatcher-protected-paths*~ (wildcard ~core-*~ still matches — no change needed).
*** DONE Rename 13 system-* → symbolic-/neuro-/embedding-*
:PROPERTIES:
:ID: id-v050-reorg-system-names
:CREATED: [2026-05-07 Thu]
:END:
Rename mapping:
- ~system-config~~symbolic-config~
- ~system-diagnostics~~symbolic-diagnostics~
- ~system-archivist~~symbolic-archivist~
- ~system-event-orchestrator~~symbolic-events~
- ~system-self-improve~~symbolic-self-improve~
- ~system-context-manager~~symbolic-scope~
- ~system-memory~~symbolic-memory~
- ~system-model-provider~~neuro-provider~
- ~system-model-router~~neuro-router~
- ~system-model-explorer~~neuro-explorer~
- ~system-model-embedding~~embedding-backends~
- ~system-model-embedding-native~~embedding-native~
- ~system-actuator-shell~~channel-shell~
*** DONE Delete ~system-model.lisp~ (16-line wrapper)
The file delegates to ~*probabilistic-backends*~ — dead code. No skill references it directly.
*** DONE Rename 4 gateway-* → channel-*
:PROPERTIES:
:ID: id-v050-reorg-channel-names
:CREATED: [2026-05-07 Thu]
:END:
Rename mapping:
- ~gateway-cli~~channel-cli~
- ~gateway-tui-main~~channel-tui-main~
- ~gateway-tui-model~~channel-tui-state~
- ~gateway-tui-view~~channel-tui-view~
Update TUI package name: ~passepartout.gateway-tui~~passepartout.channel-tui~.
*** DONE Split ~gateway-messaging~ → 4 ~channel-*~ files
:PROPERTIES:
:ID: id-v050-reorg-messaging-split
:CREATED: [2026-05-07 Thu]
:END:
Rationale: ~gateway-messaging.lisp~ (411 lines) bundles 4 independent platforms. A Telegram fix shouldn't touch Signal/Discord/Slack code. Each platform becomes its own skill — independently loadable, hot-reloadable, self-repairable.
- ~channel-telegram~: poll + send via Telegram Bot API. ~register-actuator :telegram~.
- ~channel-signal~: poll + send via ~signal-cli~ subprocess. ~register-actuator :signal~.
- ~channel-discord~: WebSocket events + REST POST. Replace hardcoded channel IDs with env vars. ~register-actuator :discord~.
- ~channel-slack~: Events API + ~chat.postMessage~. Replace hardcoded channel IDs. ~register-actuator :slack~.
- Delete ~gateway-messaging.lisp~. Update ~DEFSKILL-FROM-ORG~ references in ~system-config~ setup wizard.
*** DONE Document core/non-core self-repair criterion
:PROPERTIES:
:ID: id-v050-reorg-docs
:CREATED: [2026-05-07 Thu]
:END:
Rationale: The criterion is the architectural foundation for every discussion about "should this be core or a skill?" It must be documented where developers look.
- New section in ~docs/ARCHITECTURE.org~: "What Makes Core Different — The Self-Repair Criterion." Explain: core = can't self-repair when corrupted, needs human. Skill = agent degrades but self-repairs.
- Include the dependency-chain analysis: which files block self-repair.
- New section in ~docs/DESIGN_DECISIONS.org~: "The Self-Repair Criterion for Core Files." Explain why ~core-context~ and heartbeat were extracted.
- Update ~README.org~ architecture summary to reflect new file map.
*** DONE Update all cross-references after reorg
:PROPERTIES:
:ID: id-v050-reorg-crossref
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- Deleted ~gateway-messaging.org/.lisp~ (split into ~channel-{telegram,signal,discord,slack}~)
- Renamed 13 ~defskill~ / ~defpackage~ names to match new file prefixes
- Renamed ~gateway-cli-input~~channel-cli-input~ (function + exports)
- Removed ~core-context~ filter from ~core-skills.lisp~
- Exported 13 new symbols for tokenizer, cost-tracker, token-economics
- ASDF ~:components~ unchanged (8 core files)
*** Verify: ASDF compiles, FiveAM suite passes, integration tests pass.
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
116 checks, 100% pass. Daemon boots and processes messages end-to-end.
*** Token Economics (implemented as skills — not core)
**Design insight: why token economics is the structural differentiator.** Passepartout's sparse-tree rendering and deterministic safety gates should produce 23x fewer tokens than competitors for equivalent coding tasks, and 1324x fewer for knowledge management. Without caching and budget enforcement, the fixed overhead per call eats these savings. The architectural advantage exists in theory but requires operational plumbing to materialize. This is now implemented and running.
*** DONE Tokenizer integration
:PROPERTIES:
:ID: id-v050-tokenizer
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- ~lisp/tokenizer.lisp~ (~org/tokenizer.org~): character-ratio heuristic per model family
- ~count-tokens~, ~model-token-ratio~, ~token-cost~, ~provider-token-cost~
- Per-model pricing table: gpt-4o-mini, claude-3-5-sonnet, deepseek-chat, llama-3.1-70b, gemini-2.0-flash, etc.
- Provider-to-model mapping for all 7 cascade backends
- 11 FiveAM tests, 100% pass
*** DONE Prompt prefix caching
:PROPERTIES:
:ID: id-v050-prefix-cache
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- ~lisp/token-economics.lisp~: ~prompt-prefix-cached~ — IDENTITY+TOOLS prefix cached via ~sxhash~
- Rebuilds only when skill load, identity config, or standing mandates change
- ~fboundp~-guarded call from ~think()~ in ~core-reason.lisp~
- 3 FiveAM tests: build, cache hit, cache miss
*** DONE Incremental context assembly
:PROPERTIES:
:ID: id-v050-incr-context
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- ~lisp/token-economics.lisp~: ~context-assemble-cached~ — skips on heartbeat/delegation
- Cache invalidated when foveal-id, scope, or memory timestamp changes
- Falls back to ~[Awareness skill not loaded]~ when ~symbolic-awareness~ not ~fboundp~
- 3 FiveAM tests: skip heartbeat, skip delegation, user-input passes through
*** DONE Per-call token budget
:PROPERTIES:
:ID: id-v050-token-budget
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- ~lisp/token-economics.lisp~: ~enforce-token-budget~ — progressive trimming
- L1: truncate logs to last 5 lines; L2: drop standing mandates; L3: summary context
- ~CONTEXT_MAX_TOKENS~ env var (default 16384)
- 2 FiveAM tests: under-budget passthrough, over-budget trim
*** DONE Cost tracking
:PROPERTIES:
:ID: id-v050-cost-tracking
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-08 Thu]
:END:
- ~lisp/cost-tracker.lisp~: ~cost-track-call~, ~cost-session-total~, ~cost-by-provider~
- Per-call cost logged: ~COST TRACKER: DEEPSEEK call: 0.0002 USD (session total: 0.0002 USD)~
- ~cost-format-budget-status~ for TUI status bar: ~[Cost: $0.00 | 3 calls]~
- 6 FiveAM tests, 100% pass
*** Module Architecture
All three modules (tokenizer, cost-tracker, token-economics) are loaded as
skills via ~skill-initialize-all~, not as core ASDF components. Calls from
~think()~ are ~fboundp~-guarded. When any module is corrupted or absent, the
agent degrades gracefully (no token counting, no cost tracking, system prompt
falls back to un-cached assembly). This satisfies the self-repair criterion.
*** Competitive Advantage Analysis — v0.5.0 Summary
Token economics is the dimension where the architecture's theoretical advantage becomes operationally real. The foveal-peripheral model and deterministic gates reduce the tokens *needed* per task; prompt caching and incremental assembly reduce the tokens *spent* per task. Combined, the 23x coding savings and 1324x knowledge management savings in the DESIGN_DECISIONS token analysis become achievable rather than aspirational.
Prompt prefix caching saves retransmitting ~500-1500 tokens per call. Incremental context assembly skips context rendering on heartbeat ticks (one per 60 seconds, saving ~200-800 tokens each). Token budget enforcement prevents silent context window overflow. Cost tracking gives the user per-call visibility into LLM spend — something no competitor provides at this level of granularity.
The minimum viable local model advantage is structural: at 2,0004,000 effective tokens (foveal-peripheral + caching), a 78B parameter model on consumer hardware is a daily driver. Competitors at 32K+ effective tokens require 70B+ parameter models and 1632 GB VRAM. Passepartout runs on a laptop GPU where competitors need a data center card or cloud API.
** v0.4.3: Shell Sandboxing & Safety Classification
The current shell safety is regex-based pattern matching — a fast pre-filter that catches obvious attacks but cannot contain sophisticated or encoded payloads. This version adds actual sandbox isolation (bubblewrap Linux namespaces) as the enforcement layer, and introduces severity classification so the rule learning system in v0.5.0 can apply different thresholds to catastrophic vs harmless operations.
*** DONE Add ~bwrap~ sandbox to shell actuator
:PROPERTIES:
:ID: id-v043-bwrap-sandbox
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-07 Thu 17:37]
:END:
Rationale: Regex-based shell safety catches obvious patterns (~rm -rf /~, ~dd if=~, ~mkfs.~) but is fundamentally bypassable with encoding (~base64 -d | bash~), indirection (~find / -exec rm {} \;~), or interpreter-based execution (~python3 -c "import os; os.system(...)"~). Bubblewrap (~bwrap~) is a 200KB unprivileged sandbox binary available on all modern Linux distributions. It creates transient Linux namespaces without root, without Docker, without daemon processes. Combined with the regex pre-filter, it provides defense-in-depth: the regex catches obvious attacks fast (no sandbox spawn), the sandbox contains sophisticated ones.
- In ~actuator-shell-execute~ (~system-actuator-shell.lisp~): detect if ~bwrap~ binary is available (~which bwrap~).
- If available: wrap command in ~bwrap --ro-bind /usr /usr --ro-bind /lib /lib --ro-bind /bin /bin --ro-bind /etc /etc --bind ~/memex ~/memex --bind /tmp /tmp --unshare-net --unshare-ipc timeout ...~.
- ~--unshare-net~: no network access within sandbox. Makes regex-based network exfiltration check redundant for sandboxed commands.
- ~--unshare-ipc~: no shared memory, no semaphore injection.
- If ~bwrap~ is unavailable: log a warning, fall back to current behavior (regex-only safety).
- The regex checks remain as a fast pre-filter — they run before spawning the sandbox.
- FiveAM test: command that reads ~/etc/shadow~ inside sandbox fails with permission error; same command in unsandboxed fallback is at least caught by path protection.
*** DONE Shell safety severity classification system
:PROPERTIES:
:ID: id-v043-severity-classification
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-07 Thu 17:37]
:END:
Rationale: The current shell safety check treats all dangerous patterns equally — ~rm -rf /~ gets the same treatment as a backtick injection in ~echo~. But not all shell operations carry the same risk. A severity classification system enables the rule learning engine (v0.5.0) to apply different thresholds: catastrophic operations are always HITL regardless of approval count, moderate operations graduate to allowed after N approvals, harmless operations are allowed by default.
- Define four severity tiers as plist keywords: ~:catastrophic~ (mkfs, dd to devices, rm -rf /, shred /dev/), ~:dangerous~ (chmod -R /, writes outside ~/memex, curl to unwhitelisted domains), ~:moderate~ (npm install, pip install, git push, writes within ~/memex), ~:harmless~ (echo, ls, cat, find without exec, grep).
- Extend ~*dispatcher-shell-blocked*~ entries from simple ~(NAME REGEX)~ to ~(NAME REGEX :SEVERITY <tier>)~.
- Extend ~dispatcher-check-shell-safety~ to return the severity alongside the matched pattern name.
- ~:catastrophic~ severity always triggers HITL approval, regardless of rule count. ~:harmless~ operations are allowed by default (skip HITL and rule learning).
- The severity classification is the foundation that ~dispatcher-learn~ (v0.5.0) builds on — learning only applies to ~:dangerous~ and ~:moderate~ tiers.
- FiveAM test: ~echo hello~ returns ~:harmless~ severity and passes through; ~mkfs.ext4 /dev/sda~ returns ~:catastrophic~ and is always blocked.
** v0.4.2: Structured Output (LLM → JSON → plist)
The current ~think()~ function asks the LLM to produce raw S-expression plists. Four pieces of defensive infrastructure (~handler-case~ around ~read-from-string~, ~markdown-strip~, ~plist-keywords-normalize~, the RCE guard test) exist because LLMs cannot reliably produce balanced, keyword-prefixed plists. The fix: use the LLM API's native function calling / tool-use feature. The LLM always returns guaranteed-valid JSON. Convert to plist deterministically at the boundary.
*** DONE Implement function-calling / tool-use API in provider requests
:PROPERTIES:
:ID: id-v042-function-calling
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-07 Thu 17:17]
:END:
Rationale: Every major provider API (OpenAI, Anthropic, Groq, DeepSeek, OpenRouter) supports function calling. The LLM is sent tool definitions as JSON Schema. It returns ~tool_calls~ with guaranteed-valid JSON arguments. This eliminates the fragile ~read-from-string~ plist parsing entirely — the probabilistic layer speaks JSON (what it was trained on), the deterministic layer speaks plists (what the code controls). Conversion happens at a narrow, well-defined boundary.
- Modify ~provider-openai-request~ in ~system-model-provider.lisp~: add optional ~:tools~ parameter. When tools are provided, include ~"tools": [...]~ and ~"tool_choice": "auto"~ in the request body.
- Parse ~tool_calls~ from the API response: extract ~function.name~ and ~function.arguments~ (guaranteed valid JSON).
- Return a new result shape: ~(:status :success :tool-calls ((:name "shell" :arguments (:cmd "echo hello"))))~ alongside or instead of ~:content~.
- For providers that don't support function calling (local Ollama): keep ~:content~ path as fallback. LLM can still return raw text.
- FiveAM test: send a request with a mock tool definition, verify the response shape.
*** DONE Wire structured tool calls into ~think()~ — JSON→plist at boundary
:PROPERTIES:
:ID: id-v042-wire-tool-calls
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-07 Thu 17:17]
:END:
Rationale: Once the provider layer returns structured ~tool-calls~, the ~think()~ function must convert them to the internal plist format that ~cognitive-verify~ and ~loop-gate-act~ expect. This is a one-way, deterministic conversion at the architectural boundary.
- Add ~json-alist-to-plist~ helper in ~core-loop-reason.lisp~: convert JSON alist (from ~cl-json:decode-json-from-string~) to keyword-prefixed plist. String keys → keywords. Nested objects recurse. JSON null → ~nil~. ~25 lines.
- In ~think()~ after ~backend-cascade-call~: if result contains ~:tool-calls~, convert each tool call's ~:arguments~ JSON to plist via ~json-alist-to-plist~, wrap in ~(:TYPE :REQUEST :PAYLOAD (:TOOL <name> :ARGS <plist> :EXPLANATION "..."))~.
- Keep the existing ~read-from-string~ path as fallback for providers that return raw text (local Ollama, streaming).
- The ~read-from-string~ path remains guarded by ~*read-eval* nil~ from v0.3.1.
- FiveAM test: JSON ~{"action":"shell","cmd":"echo hello"}~ → plist ~(:ACTION "shell" :CMD "echo hello")~ round-trip verified.
** v0.4.1: Design Cleanup
*** DONE Remove system-prompt-augment mechanism
:PROPERTIES:
:ID: id-v041-augment-removal
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-07 Thu 13:13]
:END:
Rationale: The ~system-prompt-augment~ slot on the skill struct enables skills to inject always-on text into every LLM system prompt via a ~maphash~ over ~*skill-registry*~ in ~think()~ (core-loop-reason.lisp:83-92). Only one skill uses it — ~programming-repl~ — and it does so as a backdoor: the skill's trigger is hardcoded to ~nil~, so it never fires as an active skill. Its sole contribution is injecting a REPL-first mandate into every system prompt. The other ~24 skills have nil augments and are skipped by the ~when aug-fn~ guard. This is architecturally wrong: standing mandates (always-on rules) should live in a dedicated ~*standing-mandates*~ list, not piggyback on a skill that is never triggered. The mechanism also fuels a false claim in DESIGN_DECISIONS about 3,000-8,000 tokens of overhead — the actual overhead is ~40 tokens from the one active augment.
- Remove ~system-prompt-augment~ slot from the ~skill~ defstruct and ~defskill~ macro (core-skills.org:78, core-skills.org:121-133).
- Remove the ~maphash~ skill-augments collection block from ~think()~ and the associated ~(or skill-augments "")~ injection in the system-prompt ~format~ call (core-loop-reason.org:83-95, core-loop-reason.org:196-198).
- Remove ~:system-prompt-augment #'repl-mandate~ from ~programming-repl~'s ~defskill~ (programming-repl.org:269).
- Introduce ~*standing-mandates*~ (a list of function → string generators). Inject them into the IDENTITY section of the system prompt alongside ~assistant-name~. Move ~repl-mandate~ there: ~(push #'repl-mandate *standing-mandates*)~.
- Tangle the corresponding lisp/ files.
*** DONE Fix false token-overhead claims in docs
:PROPERTIES:
:ID: id-v041-doc-fix
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-07 Thu 13:13]
:END:
Rationale: Two documents claim the ~system-prompt-augment~ mechanism can waste 3,000-8,000 tokens per think() call (DESIGN_DECISIONS line 435, ROADMAP line 504). This conflates the ~maphash~ iteration (cheap hash walk, no token cost) with the augments actually emitted (only ~programming-repl~ emits ~40 tokens; the ~when aug-fn~ guard skips the other 24 nil-augment skills). Once issue #1 above is resolved (removing the mechanism), these claims become doubly false.
- DESIGN_DECISIONS: Rewrite or remove bullet 2 under "Open Questions and Risks" (line 435). Replace with a corrected note on standing mandates via ~*standing-mandates*~.
- ROADMAP v0.5.0 intro (line 504): Remove or rewrite the claim that "system prompt overhead alone could reach 3,000-8,000 tokens per call before user input is even processed." The fixed overhead is not from skill augments — it is from the IDENTITY, TOOLS, CONTEXT, and LOGS sections, which prefix caching addresses.
*** DONE Update security vector count 9→10 in docs
:PROPERTIES:
:ID: id-v041-vector-count
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-07 Thu 14:40]
:END:
Rationale: The current dispatcher runs 10 deterministic checks (11 counting the warning-only REPL lint), but the README, ARCHITECTURE.org, and the ~dispatcher-check~ docstring all say 9. The actual count: 0=REPL-lint (warn only), 1=lisp-validation, 2=secret-path, 2b=self-build-core, 3=secret-content, 4=vault-secrets, 5=privacy-tags, 6=privacy-text, 7=shell-safety, 8=network-exfil, 8b=high-impact-approval. Ten blocking/approval checks. The vector 2b (self-build safety) and the new count must be reflected accurately in all documentation.
- Update README.org "What Makes Passepartout Different" → "nine" becomes "ten".
- Update docs/ARCHITECTURE.org Dispatcher Gate Stack table — add self-build entry.
- Update security-dispatcher.lisp:196 docstring to list all 11 vectors.
*** DONE Rewrite README — add "What is an agent?" section, revise claims
:PROPERTIES:
:ID: id-v041-readme-rewrite
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-07 Thu 14:40]
:END:
Rationale: The current README opens with competitive claims (downward cost curve, 2-3x fewer tokens) that are architecturally sound but not yet measured in the implementation. A non-engineer reader doesn't know what an AI agent is or why they'd want one. The README should lead with a short "What is an agent?" section (3-4 sentences, Wikipedia link), then "What Makes It Different" (safety, org-mode, offline — things that actually work today), then honest status of what's implemented vs planned.
- Add "What is an AI Agent?" section at top: 3-4 sentences + link to [[https://en.wikipedia.org/wiki/Software_agent][Software agent]].
- Move competitive cost/speed claims to docs/DESIGN_DECISIONS.org.
- Revise "The more you use it, the cheaper it gets" to reflect current state — architectural aspiration, not measured implementation yet.
- The Current Capabilities table and Quick Start sections stay intact.
*** DONE Register cognitive tools — 10 tools for codebase operations
:PROPERTIES:
:ID: id-v041-cognitive-tools
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-07 Thu 14:40]
:END:
Rationale: The ~def-cognitive-tool~ macro and ~*cognitive-tool-registry*~ are fully implemented but the registry is empty. The LLM sees "No tools registered" in its tool belt prompt. The agent can chat and run shell commands, but cannot search codebases, find files, eval code, run tests, or manipulate Org files. Ten cognitive tools bridge this gap and are prerequisites for the TDD workflow, org-mode additions, and evaluation harness in v0.5.0.
- New skill: ~programming-tools.org~ (~programming-tools.lisp~).
- Register 10 tools via ~def-cognitive-tool~:
1. ~search-files~ — regex search in file contents (uses ~cl-ppcre:scan~). Parameters: ~pattern~, ~path~ (dir), ~include~ (glob filter).
2. ~find-files~ — glob file matching (uses SBCL ~directory~). Parameters: ~pattern~, ~path~.
3. ~read-file~ — read file contents (uses ~uiop:read-file-string~). Parameters: ~filepath~.
4. ~write-file~ — write content to file. Parameters: ~filepath~, ~content~.
5. ~list-directory~ — list directory contents. Parameters: ~path~, ~pattern~ (optional).
6. ~run-shell~ — execute shell command (through existing shell actuator). Parameters: ~cmd~.
7. ~eval-form~ — evaluate Lisp expression in running image. Parameters: ~code~, ~package~ (optional).
8. ~run-tests~ — run FiveAM tests. Parameters: ~test-name~ (optional, nil runs all).
9. ~org-find-headline~ — find Org headline by ID or title. Parameters: ~id~ or ~title~, ~filepath~ (optional, searches memory store if not given).
10. ~org-modify-file~ — surgical text replacement in Org file (reuses existing ~org-modify~). Parameters: ~filepath~, ~old-text~, ~new-text~.
- Descriptive names rather than Unix command names — the LLM reads these in a prompt, not a terminal.
- Each tool is ~20-60 lines. ~search-files~ iterates directory, reads files, scans lines.
- FiveAM tests: each tool gets a test verifying operation on a temp directory.
*** DONE Enforce NO-HARDCODED-CONSTANTS programming standard
:PROPERTIES:
:ID: id-v041-no-hardcoded
:CREATED: [2026-05-07 Thu]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-07 Thu 14:40]
:END:
Rationale: Currently, several configurable values are hardcoded in source: the Dispatcher's rule threshold (not yet configurable), similarity thresholds, timeouts, shell max output. The user should control behavior through ~.env~, not by editing source code. This is rule #6 in the ~programming-standards.org~ skill. Each new TODO that introduces a configurable value must add it to ~.env.example~ with a documented default.
- Add ~DISPATCHER_RULE_THRESHOLD=3~ to ~.env.example~ (number of HITL approvals before a pattern becomes a permanent rule).
- Add ~RULES_FILE="$HOME/memex/system/rules.org"~ to ~.env.example~.
- Scan existing source for hardcoded configurable values — add to ~.env.example~ where missing.
- Any new TODO in v0.4.2+ that introduces a configurable value MUST include its ~.env.example~ entry.
** v0.4.0: Production Hardening — RELEASED 2026-05-06
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-06 Wed 20:56]
:END:
The features in this version were originally sequenced as v0.3.x patches but represent feature-level scope. They activate the architectural advantages designed in v0.1.0v0.3.0, harden the self-build safety boundary, and expand Passepartout's interaction surfaces beyond the terminal TUI. Each feature depends on infrastructure already in place — the wiring, the sandbox, the gate trace — and activates it.
*** DONE Semantic retrieval activation
CLOSED: [2026-05-06 Tue]
- State "DONE" from "TODO" [2026-05-06 Tue]
Rationale: Two independent failures prevent the foveal-peripheral semantic retrieval path from ever firing. First, ~context-awareness-assemble~ never passes ~:foveal-vector~ to ~context-object-render~, so the renderer receives ~nil~ for ~foveal-vector~ and the similarity calculation always returns 0.0. Second, the default ~:hashing~ embedding backend uses SHA-256 (a cryptographic hash with the avalanche property) as a similarity function. SHA-256 is designed to produce entirely different outputs for nearly identical inputs — the property that makes it secure for integrity verification is precisely what makes it useless for semantic retrieval. A content-addressed Merkle tree correctly uses SHA-256 for identity; a retrieval engine needs a similarity function, not an identity function. The infrastructure for real embeddings (~local~ with Ollama, ~openai~ with the embeddings API) is fully implemented and working — this release activates the last-mile wiring and replaces the semantically blind default with a zero-dependency algorithm that actually captures textual overlap.
- Wire ~:foveal-vector~ into ~context-awareness-assemble~: pass ~(memory-object-vector (memory-object-get foveal-id))~ as the ~:foveal-vector~ argument to the ~context-object-render~ call (one line in ~core-context.lisp:148-150~).
- Replace ~:hashing~ default backend with character-trigram Jaccard similarity. Pure Lisp, zero external dependencies, works exactly as offline as SHA-256, but captures lexical overlap: "authentication" and "authenticate" share trigrams "aut," "uth," "the," "hen," "ent," etc. The vector is a bloom filter of trigrams; cosine similarity maps to Jaccard (intersection / union). This provides real if crude semantic signal without any server.
- Rename existing ~embedding-backend-hashing~ to ~embedding-backend-sha256~ and repurpose it as an explicit ~:sha256~ provider for environments where even trivial Lisp computation is undesirable (embedded, resource-constrained). Document it as "integrity-only, no semantic retrieval capability."
- Add ~EMBEDDING_PROVIDER~ guidance to the setup wizard: explain that ~:hashing~ is the default offline fallback, ~:local~ requires Ollama with ~nomic-embed-text~, and ~:openai~ uses the paid embeddings API.
- Add FiveAM test: ingest two semantically related nodes ("implement login form" and "add password authentication"), verify cosine similarity > 0.0 with the trigram backend.
*** DONE Self-build safety boundary
CLOSED: [2026-05-06 Tue]
- State "DONE" from "TODO" [2026-05-06 Tue]
Rationale: Self-building (the agent modifying its own source code) begins at v0.10.0 when the tool ecosystem and test runner are in place. But self-building without path-level write protection means the agent can modify the very pipeline code that is currently executing — the ~core-*~ files that implement the Perceive-Reason-Act cycle, the Merkle-tree memory, the skill engine loader, and the Dispatcher gate stack itself. A hallucination or a logic error during self-building that corrupts ~core-loop-reason.lisp~ destroys the agent's ability to reason about and fix the corruption. The "thin harness" is not privileged code in the architectural sense (homoiconicity means any code can be modified at runtime), but it must be *protected* code — modifications to the harness require a human in the loop, enforced by the Dispatcher's path-protection gate, not by convention.
This is the corollary to "thin harness, fat skills": the harness is thin enough to be auditable by a human, and the Dispatcher ensures it stays that way. Skills and system modules expand freely; the core contracts to a minimal, protected kernel.
- Add ~core-*~ patterns to ~*dispatcher-protected-paths*~: ~core-*.org~, ~core-*.lisp~, and their tangled equivalents. Any file write, file read-that-prefaces-a-write, or shell command targeting these paths triggers the Dispatcher's blocking gate.
- The blocked action produces a Flight Plan (HITL approval required). The human reviews the proposed core change in an Org buffer before approving. This is the same mechanism that governs shell commands and network exfiltration — the core protection is a path-specific instance of the existing gate, not a new gate.
- Implement a ~SELF_BUILD_MODE~ env var. When ~SELF_BUILD_MODE=true~ (default ~false~):
- Core path protection is active (writes blocked, HITL required)
- Non-core writes proceed through the standard Dispatcher gate (permissions table + policy + Dispatcher)
- ~SELF_BUILD_MODE=false~ disables core protection entirely — useful during initial development when the human is manually editing core files and doesn't want every save to trigger a Flight Plan
- Telemetry: track self-build actions (core modifications proposed, core modifications approved, core modifications denied). This is the dataset that the Dispatcher's learning system uses in v3.0.0 to understand which core modifications are safe enough to automate.
- Add FiveAM test: simulate a write to ~core-loop.lisp~, verify the Dispatcher returns a ~:LOG~ rejection with ~"protected path"~ in the message.
*** DONE TUI Differentiator Visualization
CLOSED: [2026-05-06 Tue]
- State "DONE" from "TODO" [2026-05-06 Tue]
Rationale: Three architectural elements exist today in the daemon that no competitor can render — the Dispatcher gate trace, the foveal-peripheral focus map, and the rules-learned counter. All three run in pure Lisp with 0 LLM tokens. None are visible to the user. Making them visible turns Passepartout's architecture from an internal mechanism into a trust-building UX — the user sees exactly which safety gates passed, exactly what the agent is focusing on, and exactly how many rules the Dispatcher has learned from their decisions. No competitor can ship this because none has deterministic gates to trace, foveal-peripheral context to map, or a rule-synthesizing Dispatcher to count.
- Gate trace per action: extend the daemon's response plist to include ~:gate-trace~ — a list of ~(:gate <name> :result <:passed | :blocked | :approval>)~ entries produced by ~cognitive-verify~. The TUI renders each entry as a colored line below the corresponding agent message: green ~✓ Dispatcher: path allowed~, red ~✗ Dispatcher: blocked (shell safety)~, yellow ~→ HITL required: /approve HITL-ab12~. Gate trace lines are dim and collapsible (press Tab on a message to toggle trace visibility). This turns the invisible ten-vector safety gate into the user's primary trust mechanism.
- Focus map in status bar: add a second status bar line showing ~[Focus: core-loop.lisp:think()] [Scope: passepartout] [3 related nodes]~. The daemon already tracks ~foveal-id~ and ~*scope-resolver*~ in the signal plist; the TUI reads these from the most recent response and renders them. Related node count comes from the number of objects with cosine similarity ≥ threshold in the last context assembly. This shows the user *what the agent is looking at* — the single biggest trust gap in AI agents.
- Rule counter in status bar: ~[Rules: 47]~. The Dispatcher's ~*hitl-pending*~ hash table and approved/disallowed memory-object entries provide the count — every HITL decision that produces a rule increments it. The TUI reads the count from a new daemon response field ~:rule-count~. The user watches the counter tick up as they teach the agent their preferences.
- Expanded theme: replace the 7-flat-color ~*tui-theme*~ with a 25-color layered system organized by message category (roles, content types, tool visibility, gate states, status). See the design discussion for the full color mapping. Implement a ~/theme <name>~ command that swaps between named presets (~dark~, ~light~, ~solarized~, ~gruvbox~). Theme change persists to disk and reloads on next session.
- Add FiveAM tests: gate trace renders correctly for pass/block/approval states; focus map updates when ~foveal-id~ changes; rule counter increments on HITL approval.
*** DONE Gateway QA, Discord, Slack + Emacs Bridge
CLOSED: [2026-05-06 Tue]
- State "DONE" from "TODO" [2026-05-06 Tue]
Rationale: Passepartout currently has Telegram and Signal gateways in the codebase, both untested. The setup wizard has Slack as a configurable option with no implementation. Two messaging channels is not competitive — OpenClaw has 25+, Hermes Agent has 6+. But more critically: the Lisp crowd is Passepartout's natural audience, and they live in Emacs. An Emacs bridge that speaks the framed TCP protocol is trivial to implement (the protocol is ~200 lines of Lisp; porting to elisp is straightforward) and turns every Emacs buffer into a Passepartout interaction surface. This is not the deep Emacs integration of v0.11.2 (where the agent controls Emacs) — this is Emacs controlling the agent over TCP. The Emacs user selects a region, hits ~M-x passepartout-send-region~, and the agent responds in a dedicated buffer. They never leave their editor.
Gateway:
- Integration tests for Telegram gateway: mock the Telegram Bot API, verify message send (POST ~/sendMessage~) and receive (GET ~/getUpdates~) round-trip. Verify HITL commands (~/approve~, ~/deny~) are intercepted before injection.
- Integration tests for Signal gateway: mock ~signal-cli~ output, verify JSON message parsing and polling loop. Verify send path constructs correct ~signal-cli send~ arguments.
- Add Discord gateway: Discord Bot API (REST + Gateway WebSocket for real-time messages). Register bot, handle ~MESSAGE_CREATE~ events, send via ~POST /channels/{id}/messages~. Map Discord mentions to ~:user-input~ signals. HITL commands work identically to Telegram.
- Add Slack gateway: Slack Events API + Web API. Subscribe to ~message.im~ events, send via ~chat.postMessage~. Reuse the SLACK_TOKEN config key already present in the setup wizard.
- Each gateway is a skill under ~passepartout.skills.gateway-<platform>~ — jail-loaded, hot-reloadable, sandbox-verified.
- Gateway configuration surfaced in the setup wizard: after entering a token, offer "send a test message to yourself" as a connection verification step. Surface the result as a green ✓ or red ✗ with the error detail.
- Gateway status displayed in ~messaging-list~: platform, configured (yes/no), gateway active (yes/no), last message received (timestamp).
Emacs Bridge:
- Elisp package: ~passepartout.el~. Connects to daemon on localhost:9105 via ~make-network-process~ (TCP).
- Sends: framed plist protocol identical to the TUI (~frame-message~ ported to elisp — write hex length prefix, write prini'd plist). The daemon does not know or care whether the client is the Croatoan TUI, the CLI, or Emacs.
- Receives: daemon responses arrive in a ~passepartout-response~ buffer. Each response is rendered as an Org headline: role prefix, timestamp, content. Gate trace (from v0.4.0) is rendered as property drawer entries under the headline.
- ~M-x passepartout-send-region~: sends the selected region as a ~:user-input~ signal with the current buffer's file path as context.
- ~M-x passepartout-send-buffer~: sends the entire buffer.
- ~M-x passepartout-focus~: sets the foveal focus to the Org headline at point (extracts ~:ID:~ property, sends ~:point-update~ signal). Equivalent to the TUI's ~/focus~ command.
- ~M-x passepartout-approve~ / ~M-x passepartout-deny~: prompts for HITL token and sends approval/denial.
- Agent modifies an Org file → Emacs receives ~:buffer-update~ via the bridge → the buffer is refreshed (~revert-buffer~ or targeted replacement).
- The Emacs bridge is the daily driver for Lisp users. The TUI remains for non-Emacs users and for the differentiator visualizations. Emacs users get the gate trace and focus map as Org property drawers in the response buffer — same data, elisp-native rendering.
**** DONE Native embedding inference
CLOSED: [2026-05-07 Thu]
Implemented: in-process embedding inference via CFFI binding to llama.cpp.
- FFI binding to llama.cpp's current (non-deprecated) embedding API via a C wrapper library (~/usr/local/lib/libllama_wrap.so~) that bridges CFFI pointer params to llama.cpp struct-by-value calls
- Builds on ~/usr/local/lib/libllama.so~ (llama.cpp shared library)
- Ship nomic-embed-text-v1.5 (80MB Q4_K_M GGUF) as the bundled embedding model. 768-dimensional vectors (nomic-bert, 12 layers), CPU-friendly, <100ms per document on any modern CPU
- ~EMBEDDING_PROVIDER=native~ enables the native backend; model preloads at daemon startup (~30s)
- Lazy loading via ~*embedding-backend* :native~ also works (first call blocks ~45s for model init)
- C wrapper functions: ~llama_wrap_model_load~, ~llama_wrap_new_context~, ~llama_wrap_encode~, ~llama_wrap_batch_init/free~
- Struct sizes verified via C sizeof/offsetof: llama_model_params (72B), llama_context_params (136B), llama_batch (56B)
- BERT pooling: uses ~llama_get_embeddings_seq~ for sequence-level embedding
- ~sb-int:set-floating-point-modes :traps nil~ required before any llama.cpp call (FPU state conflict)
- ~llama_backend_init~ required before model load
- ~llama_model_get_vocab~ + ~llama_vocab_n_tokens~ replaces deprecated ~llama_n_vocab~
- ~llama_tokenize~ takes ~vocab*~ not ~model*~ (API change since earlier llama.cpp versions)
- Exports: ~embedding-backend-native~, ~embedding-native-load-model~, ~embedding-native-unload~, ~embedding-native-ensure-loaded~, ~embedding-native-get-dim~
- FiveAM tests: availability, loading, dimensions (768), self-similarity (1.0), semantic similarity ranking
- The trigram Jaccard backend remains as the default fallback for zero-config deployments
- State "DONE" from "TODO" [2026-05-07 Thu]
*** Competitive Advantage Analysis — v0.4.0 Summary
Production hardening is the process of turning architectural potential into operational strength. The semantic retrieval fix activates the foveal-peripheral model's full power: deep nodes that are topically related to the user's focus now surface automatically. Without this, the context model is "dumb truncation at depth 2." With it, it's genuine semantic awareness — and since the retrieval is deterministic (in-image vector math, zero LLM tokens), the cost advantage over competitors' LLM-assisted search compounds with every query.
The self-build safety boundary is a capability no competitor provides: the agent cannot modify its own brain stem without human review. The ~core-*~ path protection means the Dispatcher draws a line at the filesystem level, not the policy document level. Claude Code, OpenClaw, and Hermes all allow agents to modify their own source files without distinction between application code and runtime code. Passepartout's Dispatcher prevents modification of the very pipeline that implements the Perceive-Reason-Act cycle, the Merkle-tree memory, the skill engine loader, and the Dispatcher gate stack itself. This is the operational realization of "thin harness, fat skills" — the harness is thin enough to be auditable by a human, and the Dispatcher ensures it stays that way.
The TUI differentiator visualizations are Passepartout's permanent UX advantage. The gate trace, focus map, and rule counter are UX elements that only make sense in Passepartout's architecture — deterministic gates, foveal-peripheral context, and Dispatcher rule synthesis exist nowhere else. No competitor can ship this because none has deterministic gates to trace, foveal-peripheral context to map, or a rule-synthesizing Dispatcher to count. Combined with the TUI critical fixes from v0.3.3, the TUI is competitive on usability and uniquely informative on safety and context transparency.
The messaging gateways and Emacs bridge expand Passepartout's interaction surface from a single terminal TUI to four surfaces: terminal, Telegram/Signal/Discord/Slack messaging, Emacs, and voice (via the voice gateway in v0.10.3). The Emacs bridge is strategically critical — the Lisp crowd is Passepartout's natural audience, and they live in Emacs. An Emacs bridge that speaks the framed TCP protocol turns every Emacs buffer into a Passepartout interaction surface. Combined with the gate trace and focus map rendered as Org property drawers in the response buffer, Emacs users get the same differentiator visualizations as TUI users — same data, elisp-native rendering.
** v0.3.0: Event Orchestration + HITL — RELEASED 2026-05-06
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-06 Wed 15:50]
:END:
Unified control plane, Human-in-the-Loop state management, and backfill remediation
for stubs and gaps from v0.1.0/v0.2.0. Security hardening followed as
v0.3.1v0.3.3 point releases.
*** DONE Secret Exposure Gate, Shell Safety, Lisp Validation
:PROPERTIES:
:ID: id-aa53c128-195b-42d4-9838-2def59faf7cf
:CREATED: [2026-05-02 Sat]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-02 Sat]
:END:
*** DONE Multi-distro deployment (Debian+Fedora, systemd, Docker)
:PROPERTIES:
:ID: id-783df999-f7fe-45c8-896d-2fd07c604d64
:CREATED: [2026-05-02 Sat]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-02 Sat]
:END:
*** DONE Project rename to Passepartout (files, packages, env vars)
:PROPERTIES:
:ID: id-91724874-aa0d-4804-9220-8bc5551f1366
:CREATED: [2026-05-02 Sat]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-02 Sat]
:END:
*** DONE 31 org files with full literate prose
:PROPERTIES:
:ID: id-597b2a92-aac6-481a-b2c4-4f9842ced97c
:CREATED: [2026-05-02 Sat]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-02 Sat]
:END:
*** DONE Human-in-the-Loop (HITL)
CLOSED: [2026-05-03 Sun 14:00]
:PROPERTIES:
:ID: id-hitl-complete
:CREATED: [2026-05-02 Sat]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-03 Sun 14:00]
:END:
Continuation-based interaction. The agent can suspend its cognitive loop to ask for
permission or clarification and resume precisely where it left off. Builds on the
dispatcher's existing Flight Plan mechanism.
*** DONE Event Orchestrator (unified hooks+cron+routing)
:PROPERTIES:
:ID: id-d35aea3d-2e5f-4a12-a9b0-1c2d3e4f5a6b
:CREATED: [2026-05-02 Sat 14:00]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-02 Sat 22:36]
:END:
Unified control plane for hooks, cron, and complexity-based routing.
- *hook-registry* + *cron-registry* + tier classifier
- Hooks via ~#+HOOK:~ Org-mode properties
- Three complexity tiers: ~:REFLEX~ (no LLM), ~:COGNITION~ (light LLM), ~:REASONING~ (full LLM)
- Hooked into heartbeat for cron processing
- Rule-based tier classifier (overrideable via ~*tier-classifier*~)
*** DONE Context Manager (project scoping)
CLOSED: [2026-05-05 Tue]
:PROPERTIES:
:ID: id-context-manager-scoping
:CREATED: [2026-05-05 Tue]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-05 Tue]
:END:
Stack-based project focusing with persistence.
- ~push-context~/~pop-context~/~with-context~ stack operations
- ~current-scope~ wired into perceive gate ~*scope-resolver*~
- ~/focus~/~/scope~/~/unfocus~ TUI commands
- Context stack persisted to ~~/.cache/passepartout/context.lisp~, auto-restores on boot
*** DONE Model-Tier Routing (cost optimization)
CLOSED: [2026-05-03 Sun 16:00]
:PROPERTIES:
:ID: id-model-tier-routing
:CREATED: [2026-05-02 Sat 23:00]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-03 Sun 16:00]
:END:
Extend ~*model-selector*~ for quadrant-based routing with per-slot provider cascades.
- Privacy filter (local-only for @personal content) — top priority
- Quadrant tagging (foreground/background × probabilistic/deterministic)
- Complexity classifier (code/plan/chat/background slots), each with its own provider cascade
- Model-selector skill registers into =*model-selector*= hook
Deferred to v0.5.0: budget tracking per request, per-session cost monitoring.
Deferred to v0.11.0: TUI /config command for cascade configuration (env vars for now).
*** DONE Memory Scope Segmentation
CLOSED: [2026-05-03 Sun 16:30]
:PROPERTIES:
:ID: id-memory-scope-segmentation
:CREATED: [2026-05-02 Sat 23:00]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-03 Sun 16:30]
:END:
Extend memory-object with ~:scope~ property.
- ~:memex~ (permanent knowledge), ~:session~ (ephemeral), ~:project~ (current work)
- Scope-aware retrieval in memory layer
*** DONE Asynchronous Embedding Gateway
CLOSED: [2026-05-05 Tue]
:PROPERTIES:
:ID: id-async-embedding
:CREATED: [2026-05-02 Sat 23:00]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-05 Tue]
:END:
Provider-agnostic vector generation (Ollama, OpenAI, hashing fallback).
- Three backends: local (Ollama-compatible), openai (/v1/embeddings), hashing (SHA-256)
- ~embeddings-compute~ and ~*embedding-backend*~ for runtime provider selection
- ~ingest-ast~ populates vectors at object creation time
- ~mark-vector-stale~ marks vectors as ~:pending~ and queues for re-embedding
- ~embed-all-pending~ drains queue, computes vectors, stores in ~*memory-store*~
- Cron job registered with orchestrator: runs every 10m on ~:reflex~ tier
- ~EMBEDDING_PROVIDER~ env var for provider selection
- Registered as proper skill (~defskill~~:passepartout-system-model-embedding~)
*Note:* The default ~:hashing~ backend uses SHA-256-derived vectors. SHA-256 is a
cryptographic hash with the avalanche property — one-bit input differences produce
entirely different outputs. This makes it a correct integrity check (Merkle tree)
but an incorrect similarity function (semantic retrieval). v0.4.0 replaces it with
a zero-dependency lexical similarity algorithm that actually captures textual
overlap while remaining offline-capable.
*** DONE TUI Experience (Daily Driver Quality)
CLOSED: [2026-05-05 Tue]
:PROPERTIES:
:ID: id-tui-experience
:CREATED: [2026-05-02 Sat 23:00]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-05 Tue]
:END:
All P0-P4 items implemented:
- P0: Chat scrollback (Page Up/Down), Input history (up/down arrows)
- P1: Status bar (connection, mode, msg count, scroll, activity indicator)
- P1: Message rendering (timestamps, colors, role icons)
- P2: Command palette (~/help~ command listing)
- P2: Multi-line input (~\ + Enter~ inserts newline)
- P3: Background activity indicator (~…thinking~ spinner)
- P4: Tab completion for all ~/~~ commands
- P4: Configurable theme (~*tui-theme*~ plist, ~~/theme~~ command)
*** DONE v0.2.x Backfill Remediation (stubs and gaps)
CLOSED: [2026-05-03 Sun]
:PROPERTIES:
:ID: id-v02x-remediation
:CREATED: [2026-05-03 Sun]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-03 Sun]
:END:
- P0: vault-get-secret / vault-set-secret wrappers (one-line delegation to vault-get/vault-set with ~:type :secret~)
- P0: system-archivist Scribe + Gardener (distill daily logs → atomic notes; scan broken links, orphaned memory-objects)
- P0: system-self-improve surgical edit + error fix (read → replace → snapshot → write → balance → tangle → reload)
- P0: programming-org org-modify + org-ast-render (locate node by ID, apply changes; convert plist AST → Org text)
- P0: programming-literate balance check + tangle sync (verify balanced parens in source blocks; verify .lisp matches tangled output)
- P1: system-event-orchestrator bootstrap (scan Org files for HOOK/CRON properties, register via existing registries)
- P1: system-memory introspection (structured statistics: object count by type, TODO distribution, orphans, snapshots)
- P1: path relic skills/ → lisp/ (update skill-initialize-all and context-skill-source to resolve against lisp/ directory)
- P2: core-context semantic retrieval (populate org-object-vector at ingest; fallback: TF-IDF bag-of-words)
- P2: core-context subtree-based skill source loading (context-skill-subtree for targeted retrieval by heading name)
- P3: Variable name drift normalization (*memory* vs *memory-store*, *skills-registry* vs *skill-registry*)
- P4: Eliminate STYLE-WARNINGs from setup output (reorder defuns for same-file forward references; accept cross-skill references)
*** DONE Project Renaming (Bouncer → Dispatcher)
:PROPERTIES:
:ID: id-9e779580-287b-b3d1-37b9-bcefd750bf9e
:CREATED: [2026-05-01 Fri 15:40]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-02 Sat 22:00]
:END:
The Dispatcher's role has evolved beyond security guard. It is the seed of the deterministic engine — it learns to execute procedures without invoking the neural net.
*** DONE Parser RCE elimination
:PROPERTIES:
:ID: id-v031-parser-rce
:CREATED: [2026-05-06 Wed]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-06 Wed 16:38]
:END:
Rationale: SBCL's default ~*read-eval* accessor is ~t~, enabling the ~#.~ reader macro to execute arbitrary Lisp forms during parsing. Three code paths in the current codebase process untrusted input with ~read-from-string~ or ~read~ without binding ~*read-eval*~ to ~nil~. Each represents a remote code execution vector that bypasses all deterministic safety gates — the Dispatcher's shell safety check, path protection, secret scanning, and network exfiltration detection never execute because the malicious form is evaluated during parsing, before the action plist is even constructed.
- Wrap ~read-from-string~ in ~think()~ (core-loop-reason.lisp:102) with ~(let ((*read-eval* nil)) ...)~ — LLM output is untrusted by definition; parsing it must never execute code. The markdown-strip regex already runs, so the fix immediately follows it.
- Wrap ~read~ in ~load-memory-from-disk~ (core-memory.lisp:143) with ~(let ((*read-eval* nil)) ...)~ — the ~memory.snap~ file lives in ~~/ by default and could be corrupted or planted.
- Wrap ~read-from-string~ in ~action-system-execute~ (core-loop-act.lisp:62) with ~(let ((*read-eval* nil)) ...)~ — the ~:system :eval~ path executes untrusted payload code. Explicitly assert that this path requires the Dispatcher's approval gate.
- Add FiveAM test: inject ~"(#.(shell \"echo pwned\"))"~ into the ~think()~ pipeline and assert no shell execution occurs.
*** DONE Shell safety & actuator sandboxing
:PROPERTIES:
:ID: id-v032-shell-sandbox
:CREATED: [2026-05-06 Wed]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-06 Wed 16:46]
:END:
Rationale: The ~:system :eval~ actuator path is currently unchecked by the Dispatcher's approval gate — only ~:shell~ and ~:tool "shell"~ trigger HITL. The shell actuator wraps commands through double ~bash -c~ nesting (~system-actuator-shell.lisp:10~), where Lisp's ~format~ with ~s~ produces S-expression-safe strings, not shell-safe strings. A command containing quotes or substitution characters can break out. Additionally, skill files loaded via ~skill-initialize-all~ execute arbitrary Lisp in jailed packages — a skill file containing ~(uiop:run-program "dangerous")~ executes immediately on load before any gate can inspect it.
- Fix shell double-wrapping: remove the outer ~bash -c~ in ~actuator-shell-execute~; pass the command string directly to ~uiop:run-program~ with ~:force-shell nil~. The timeout wrapping remains via the OS ~timeout~ binary.
- Extend the Dispatcher approval requirement to the ~:system :eval~ path (currently only ~:shell~ and ~:tool "shell"~ trigger HITL). An unbounded ~eval~ should require the same Flight Plan approval as a shell command.
- Add skill sandbox mode for ~skill-initialize-all~: load each skill's code into a temporary jailed package, run the registered trigger function in isolation, verify it imports no restricted symbols (from CL package: ~run-program~, ~shell~, ~run-shell-command~), then promote to the live registry on pass.
- Add FiveAM test: register a skill containing ~(uiop:run-program "echo test")~ in the body and verify the sandbox blocks its promotion.
*** DONE TUI Critical Fixes
:PROPERTIES:
:ID: id-v033-tui-fixes
:CREATED: [2026-05-06 Wed]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-05-06 Wed 17:59]
:END:
Rationale: The TUI is Passepartout's only interface. OpenClaw distributes across 25+ messaging channels with voice, Canvas, and macOS/iOS apps. Hermes Agent ships multiline editing, slash-command autocomplete, conversation history, interrupt-and-redirect, and streaming tool output in its TUI. Passepartout's Croatoan TUI must carry the product alone, and it currently lacks word wrap, cursor movement, resize handling, connection-loss feedback, a quit command, and persistent history. None of these fixes require daemon changes — they are pure client-side Croatoan work that closes the gap from "proof of concept" to "daily driver."
- Word wrap in ~view-chat~: every LLM response longer than the terminal width is silently truncated to one line. Croatoan supports multi-line rendering; ~view-chat~ must calculate per-message line height, adjust visible-message count accordingly, and scroll per message-line rather than per message. For very long messages, add a pager mode where pressing Enter on a message opens it in a scrollable overlay.
- Left/Right cursor in input: add ~:left~ and ~:right~ key handlers that move a cursor position index within the ~:input-buffer~ list. Characters are inserted at the cursor position, not always appended. Backspace deletes at the cursor position.
- SIGWINCH handler: register a terminal resize signal. On resize, re-measure the root window, destroy and recreate the three sub-windows (~sw~, ~cw~, ~iw~), set all dirty flags to ~t~, and force a full redraw.
- Connection-loss detection: the reader thread currently polls ~recv-daemon~ silently on EOF. On disconnection, queue a ~:disconnected~ event, set ~:connected~ to ~nil~, clear ~:busy~, add a red system message "Connection lost — run /reconnect to retry." The ~:disconnected~ event dirties the status bar to show the status indicator.
- ~/quit~ command + persistent history: on ~/quit~, save ~:input-history~ to ~~/.cache/passepartout/history~ (one line per entry, most recent first), send a goodbye handshake to the daemon, close the socket, and exit the main loop cleanly. On startup, load history from the save file if it exists.
- Scroll offset clamping: clamp ~:scroll-offset~ to ~(max 0 (- msg-count visible-lines))~. The status bar shows ~"msgs:12/45"~ (visible / total) rather than ~"msgs:45"~ (total only) so the user knows when they've scrolled past the oldest message.
- Message list storage: replace the O(n²) ~(nth i msgs)~ list indexing with a simple adjustable vector. ~add-msg~ appends; ~view-chat~ iterates with ~aref~. The vector is resized as needed. Same API surface, 100x speedup on message-heavy sessions.
- Add FiveAM tests: word-wrap produces correct line count for a 200-character string at 80-column width; cursor left/right wraps at buffer boundaries; SIGWINCH preserves message state; ~/quit~ saves and restores history.
** v0.2.0: Interactive Refinement — RELEASED 2026-04-29
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-29 Wed 20:17]
:END:
The "Brain" meets the "Machine." Standardization and professionalization of the user interface and environment.
*** DONE Text User Interface (Croatoan-based, styled, scrollable)
:PROPERTIES:
:ID: id-57cef382-fe14-42e6-aade-03e05e3e920b
:CREATED: [2026-04-28 Tue]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-29 Wed]
:END:
The Croatoan-based TUI with model-view separation and dirty-flag rendering is the foundation for all TUI improvements: word wrap in v0.3.3, gate trace in v0.4.0, tool visualization in v0.8.1, and streaming in v0.7.1.
*** DONE Self-editing (error detection, surgical fix, hot-reload)
:PROPERTIES:
:ID: id-459b8275-9979-4d0f-8d61-a9af883930d4
:CREATED: [2026-04-23 Wed]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-29 Wed]
:END:
The surgical edit + tangle + hot-reload pipeline (text replace → tangle → compile → load) established the self-modification capability that makes the Skill Creator (v0.9.0) safe — skills are generated, tangled, loaded, and verified in the same loop.
*** DONE Enhanced utilities (structural Lisp/Org manipulation + REPL)
:PROPERTIES:
:ID: id-23f37c0d-4e77-4dc3-ab43-52a5987eb426
:CREATED: [2026-04-23 Wed]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-29 Wed]
:END:
Structural Lisp/Org manipulation tools are the primitives the self-improve module (v0.2.0) and the programming skills (literate block extraction, syntax validation) build on.
*** DONE Onboarding wizard (modular Lisp setup for LLM providers)
:PROPERTIES:
:ID: id-bd497de7-3533-4056-b89f-2c992d2ea28b
:CREATED: [2026-04-28 Tue]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-29 Wed]
:END:
The setup wizard established the "works out of the box" constraint that the gateway QA (v0.4.0) and Emacs bridge (v0.4.0) onboarding flows follow.
*** DONE Memory rollback (snapshot and restore)
:PROPERTIES:
:ID: id-fd2fb6e3-03e7-4e22-b9e9-a7eecfd06718
:CREATED: [2026-04-12 Sun]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-29 Wed]
:END:
Copy-on-write snapshots (deep-copying the memory hash table on every write) gave the pipeline crash recovery. The snapshot mechanism is the root of MVCC concurrency (v0.9.0).
** v0.1.0: The Autonomous Foundation — RELEASED 2026-04-20
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-20 Mon 19:05]
:END:
The secure, auditable Lisp kernel. All core infrastructure in place.
*** DONE Perceive-Reason-Act pipeline
:PROPERTIES:
:ID: id-06f10b9a-4054-4dea-a927-b0935fbdcd2f
:CREATED: [2026-03-22 Sun]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-20 Mon]
:END:
This established the three-stage cognitive cycle that all later features plug into. The pipeline is the invariant — skills, gates, actuators, and clients all compose through it.
*** DONE Skills engine with jailed loading
:PROPERTIES:
:ID: id-dc83944f-3923-4142-b324-c317dacd6b0b
:CREATED: [2026-03-22 Sun]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-20 Mon]
:END:
This made the "thin harness, fat skills" identity operational. Skills loading into jailed packages (v0.1.0) is the foundation for the skill sandbox mode (v0.3.2) and the Skill Creator (v0.9.0).
*** DONE Policy skill (6 invariants)
:PROPERTIES:
:ID: id-929c84b7-d6ae-42b9-a8b5-d9df962db826
:CREATED: [2026-03-22 Sun]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-20 Mon]
:END:
This established the "explanation required" invariant that gates stack above. The policy gate (priority 500) runs first and sets the precedent that every action must justify itself.
*** DONE Memory (memory-object + Merkle hashing)
:PROPERTIES:
:ID: id-3a96b384-cacf-4da0-8faa-1647739feba9
:CREATED: [2026-03-22 Sun]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-20 Mon]
:END:
The Merkle tree with content-addressed hashing made copy-on-write snapshots (v0.2.0) and MVCC concurrency (v0.9.0) possible. The hash-as-identity property also feeds directly into the foveal-peripheral model's semantic retrieval.
*** DONE Scribe + Gardener background workers
:PROPERTIES:
:ID: id-3f618a38-ec23-4034-ba3c-ef272e212e2b
:CREATED: [2026-03-22 Sun]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-20 Mon]
:END:
These background workers established the heartbeat-driven maintenance pattern. The event orchestrator (v0.3.0) generalizes this into hooks and cron jobs.
*** DONE LLM gateway (OpenRouter, Ollama)
:PROPERTIES:
:ID: id-f5d870e2-cbd2-4c00-a8d4-174ab4118afc
:CREATED: [2026-04-11 Sat]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-20 Mon]
:END:
The provider-agnostic cascade pattern established in v0.1.0 makes the model-tier router (v0.3.0), privacy-aware routing (v0.3.0), and consensus loop (v0.11.0) possible — they all build on the same ~backend-cascade-call~ abstraction.
*** DONE Shell actuator, Emacs bridge, credentials vault
:PROPERTIES:
:ID: id-7ca3167f-8353-4bb7-8b97-c039017716b0
:CREATED: [2026-04-11 Sat]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-20 Mon]
:END:
The actuator registry pattern makes MCP tools (v0.10.0) possible — they register the same way.
*** DONE FiveAM test suite
:PROPERTIES:
:ID: id-925d4180-764b-4219-8bdc-8e1849572da1
:CREATED: [2026-04-11 Sat]
:END:
:LOGBOOK:
- State "DONE" from "TODO" [2026-04-20 Mon]
:END:
The test infrastructure established in v0.1.0 becomes the TDD runner (v0.12.0) and the SWE-bench harness (v0.12.0).
* Future Work
See [[file:docs/ROADMAP.org][ROADMAP.org]] for planned features.