Files
passepartout/docs/ARCHITECTURE.org
Amr Gharbeia 908936d4d3 rename gateway-* → system-model-* + gateway-messaging, de-ollama, add system-model-explorer
- Rename gateway-provider → system-model-provider (generic :local provider, no hardcoded ollama)
- Rename gateway-llm → system-model (model-request dispatcher)
- Rename system-embedding-gateway → system-model-embedding
- Rename gateway-manager → gateway-messaging (public api renamed to messaging-*)
- Add system-model-explorer (model discovery via OpenRouter API, cached, per-slot recommendations)
- Fix skill loader export: replace prefix-matching with fbound/boundp-based export (20 skills now export)
- Add model-router to skill-loader exclusion list (loaded via CLI)
- De-ollama: remove hardcoded assumed-available patterns from provider pipeline
- Default cascade: cloud-only (openrouter, openai, groq, gemini, deepseek, nvidia, anthropic)
- Env example: add LOCAL_BASE_URL, fix cascade order
- All org files updated with architectural prose (literate programming)
2026-05-04 09:58:59 -04:00

92 lines
6.4 KiB
Org Mode

#+TITLE: Passepartout Architecture
#+AUTHOR: Agent
#+STARTUP: content
* The Four Quadrants
Passepartout divides cognition along two axes: **Foreground vs Background** (initiated by the user vs running autonomously) and **Probabilistic vs Deterministic** (LLM-driven vs pure Lisp logic).
| | Probabilistic (LLM) | Deterministic (Lisp) |
|----------------+-------------------------------------------------------------+------------------------------------------------------------|
| **Foreground** | Chat responses, task execution, code generation | Shell execution, file I/O, safety gates, dispatcher checks |
| **Background** | Scribe distillation, vector embedding, autonomous decisions | Heartbeat, cron jobs, memory auto-save, gateway polling |
The Probabilistic engine proposes. The Deterministic engine verifies and executes. No proposal from the LLM touches a file, runs a command, or sends a message without passing through at least one deterministic gate.
* Code Map
The project is organized into ~org/~ (source of truth) and ~lisp/~ (generated by tangle).
** Core pipeline (loaded by ASDF, committed to git)
| File | Purpose |
|------------------------------+--------------------------------------------------------------------|
| ~org/core-defpackage.org~ | Package definition and export list |
| ~org/core-skills.org~ | Skill engine: ~defskill~ macro, topological sorter, jailed loading |
| ~org/core-communication.org~ | Framed TCP protocol, actuator registry, daemon server |
| ~org/core-memory.org~ | ~memory-object~ struct, Merkle hashing, snapshots, persistence |
| ~org/core-context.org~ | Foveal-peripheral rendering, context assembly for LLM |
| ~org/core-loop-perceive.org~ | Stage 1: normalize raw signals into pipeline format |
| ~org/core-loop-reason.org~ | Stage 2: LLM proposal + deterministic verification |
| ~org/core-loop-act.org~ | Stage 3: dispatch approved actions to actuators |
| ~org/core-loop.org~ | Orchestration: process-signal, heartbeat, main entry point |
| ~org/system-diagnostics.org~ | Boot-time health check, doctor CLI |
** Skills (loaded at runtime by the skill engine)
| Category | Files | Purpose |
|------------------+-----------------------------------------------------------------------------------------------------------------------------------+---------------------------------|
| **gateway-** | ~gateway-cli~, ~gateway-messaging~, ~gateway-tui~ | External communication channels |
| **system-model-** | ~system-model-provider~, ~system-model~, ~system-model-router~, ~system-model-embedding~, ~system-model-explorer~ | LLM infrastructure |
| **security-** | ~security-dispatcher~, ~security-policy~, ~security-permissions~, ~security-vault~, ~security-validator~ | Safety and authorization |
| **programming-** | ~programming-lisp~, ~programming-org~, ~programming-standards~, ~programming-literate~, ~programming-repl~ | Lisp and Org tooling |
| **system-** | ~system-config~, ~system-archivist~, ~system-self-improve~, ~system-memory~, ~system-actuator-shell~, ~system-event-orchestrator~ | Background services |
* Pipeline Flow
Every signal moves through three stages:
```
Signal → Perceive (normalize) → Reason (think + verify) → Act (dispatch)
```
The signal is a plist: ~(:TYPE :EVENT :META (...) :PAYLOAD (:SENSOR :user-input :TEXT "..."))~
1. **Perceive** normalizes raw input from any gateway into a uniform signal
2. **Reason** calls the LLM to generate a proposal, then runs the proposal through all registered deterministic gates (sorted by priority). If a gate rejects the proposal, the rejection trace feeds back to the LLM for self-correction (up to 3 retries)
3. **Act** dispatches the approved action to the registered actuator (~:cli~, ~:tool~, ~:system~, ~:shell~, ~:telegram~, ~:signal~)
Each stage can produce feedback signals that loop back to Perceive (e.g., a tool-execute action produces a ~:tool-output~ event that becomes the next perception).
** Depth limiting
A depth counter prevents infinite loops. If a signal's depth exceeds 10, it is silently dropped. This is the circuit breaker for runaway recursive cycles.
* Skill Lifecycle
1. *Discovery:* ~skill-initialize-all~ scans the skills directory, globs for ~*.lisp~ files (excluding ~core-*~ files which are loaded by ASDF)
2. *Sorting:* ~skill-topological-sort~ orders skills by their ~#+DEPENDS_ON:~ declarations
3. *Loading:* Each skill is loaded into a jailed package (~passepartout.skills.<skill-name>~). The loader removes ~in-package~ forms, evaluates the remaining code in the jailed package, and exports symbols matching the skill's short name to ~passepartout~
4. *Registration* The skill's ~defskill~ call creates a ~skill~ struct in ~*skill-registry*~, registering its trigger function, probabilistic prompt generator, deterministic gate, and system-prompt augment
5. *Triggering:* On each cognitive cycle, ~skill-triggered-find~ iterates the registry and returns the highest-priority skill whose trigger matches the context
6. *Hot-reload:* A skill can be replaced at runtime by loading a new version into its jailed package — no restart needed
* Communication protocol Format
All communication between the daemon and its gateways (TUI, CLI, Emacs) uses length-prefixed plists over TCP:
```
00002C(:TYPE :EVENT :PAYLOAD (:ACTION :handshake :VERSION "0.2.0"))
```
The 6-character hex prefix encodes the payload length. The payload is a ~prin1~-serialized plist. ~*read-eval*~ is bound to nil on the receiving end to prevent code injection.
** Standard message envelope:
| Key | Value | Meaning |
|-----|-------|---------|
| ~:TYPE~ | ~:REQUEST~, ~:EVENT~, ~:RESPONSE~, ~:LOG~, ~:STATUS~ | Message category |
| ~:META~ | plist | ~:SOURCE~, ~:SESSION-ID~, ~:reply-stream~ |
| ~:PAYLOAD~ | plist | Action-specific data (~:SENSOR~, ~:ACTION~, ~:TEXT~) |
| ~:DEPTH~ | integer | Recursion counter for loop prevention |