diff --git a/README.org b/README.org
index b5efb0a..e6ab75b 100644
--- a/README.org
+++ b/README.org
@@ -1,74 +1,260 @@
#+TITLE: OpenCortex: The Conductor of your Life Stack
+#+CAPTION: A neurosymbolic AI agent framework for the 100-year Memex
+#+ATTR_HTML: :width 800
+
*opencortex* is a minimalist, extensible AI agent framework designed to manage and continuously organize your personal knowledge base. It transforms a static collection of plaintext notes into a live, programmable [[https://en.wikipedia.org/wiki/Memex][Memex]]—an automated, personalized memory system where humans and AI collaborate in the exact same workspace.
* The Problem with Current AI Agents
The current ecosystem of AI agents (typically built in Python or TypeScript) is overwhelmingly built on architectural choices that prioritize rapid prototyping over long-term reliability, security, and self-modification:
-1. *The Format Trap (Markdown & JSON):* Most agents force a painful translation layer. Humans write in Markdown, which lacks a strict Abstract Syntax Tree (AST)—a rigorous, nested representation of data that machines need to parse context reliably. Machines, in turn, output JSON, which is hostile for human thought and note-taking. The result is a fractured workspace where the agent's memory and the human's memory are fundamentally incompatible.
-2. *The Language Trap (Python & TypeScript):* Python and TypeScript are fantastic for gluing together APIs, but they are poorly suited for an agent that needs to safely read, write, and execute its own code at runtime. Their underlying structures are complex and opaque, making autonomous self-editing incredibly brittle and dangerous.
-3. *The Probabilistic Trap:* Almost all modern agents rely entirely on /probabilistic/ reasoning. We ask an AI model to guess a shell command or write a Python script, and then blindly pipe that output to a terminal. Without a rigorous, /deterministic/ layer to formally verify the model's proposals before execution, these systems are fundamentally unsafe.
+** 1. The Format Trap (Markdown & JSON)
+
+Most agents force a painful translation layer. Humans write in Markdown, which lacks a strict Abstract Syntax Tree (AST)—a rigorous, nested representation of data that machines need to parse context reliably. Machines, in turn, output JSON, which is hostile for human thought and note-taking.
+
+The result is a fractured workspace where the agent's memory and the human's memory are fundamentally incompatible. You cannot see what the agent sees. The agent cannot naturally work with your notes.
+
+** 2. The Language Trap (Python & TypeScript)
+
+Python and TypeScript are fantastic for gluing together APIs, but they are poorly suited for an agent that needs to safely read, write, and execute its own code at runtime. Their underlying structures are complex and opaque, making autonomous self-editing incredibly brittle and dangerous.
+
+How do you trust an agent to modify its own Python code when Python's AST is so complex that even human programmers need IDEs to navigate it?
+
+** 3. The Probabilistic Trap
+
+Almost all modern agents rely entirely on /probabilistic/ reasoning. We ask an AI model to guess a shell command or write a Python script, and then blindly pipe that output to a terminal. Without a rigorous, /deterministic/ layer to formally verify the model's proposals before execution, these systems are fundamentally unsafe.
+
+The model might hallucinate a command. It might output valid syntax that still does something dangerous. Without a deterministic gate, there's nothing between the guess and the terminal.
* The Vision: A Modern, Homoiconic Memex
-opencortex abandons these fragile paradigms by returning to first principles and embracing two historically powerful technologies: *Org-mode* and *Common Lisp*.
+openCortex abandons these fragile paradigms by returning to first principles and embracing two historically powerful technologies: *Org-mode* and *Common Lisp*.
-** 1. Org-mode: The Universal Language
-Instead of wrestling with Markdown parsers or hiding data in opaque databases, opencortex mandates that *Org-mode is the native AST for both humans and machines.*
+** Org-mode: The Universal Language
-Org-mode is unique because it seamlessly brings together human-readable prose, structured metadata (properties and tags), lifecycle states (TODO/DONE), and executable code blocks into a single plain-text file. The code is the data, and the data is the interface. When the agent "remembers" a fact or schedules a task, it writes an Org headline. You read exactly what the agent reads.
+Instead of wrestling with Markdown parsers or hiding data in opaque databases, openCortex mandates that *Org-mode is the native AST for both humans and machines.*
-** 2. Common Lisp: The Engine of Self-Modification
-There is a beautiful irony to opencortex: Lisp was invented in 1958 specifically to achieve Artificial Intelligence, and it has been waiting nearly 70 years for /this exact moment/ in computing history.
+Org-mode is unique because it seamlessly brings together:
+- Human-readable prose
+- Structured metadata (properties and tags)
+- Lifecycle states (TODO/DONE/PLAN)
+- Executable code blocks
-Lisp possesses a unique property called *Homoiconicity*: the primary representation of the program is also a data structure (nested lists) within the language itself. Because Lisp code /is/ Lisp data, it is trivially easy for an AI to generate, manipulate, and safely evaluate new tools at runtime. This makes Lisp the ultimate, un-brittle language for a "self-writing" agent.
+...all in a single plain-text file. The code is the data, and the data is the interface. When the agent "remembers" a fact or schedules a task, it writes an Org headline. You read exactly what the agent reads.
-** 3. The Probabilistic-Deterministic Loop
-opencortex does not let AI models touch your system directly. Instead, it splits cognition into two distinct engines:
-- *The Probabilistic Engine (Neural/Dynamic):* Provides semantic understanding and dynamic reasoning. It utilizes a **Dynamic LLM Cascade** (OpenRouter, Ollama, Anthropic) to ensure the agent always has a "brain," falling back to local models if cloud services are unavailable.
-- *The Deterministic Engine (Logic/Safety):* Intercepts LLM proposals and formally verifies them against your security rules (the "Bouncer" pattern) before execution.
+This is not a compromise—it's the design principle. The agent's memory and your memory are the same format, the same file, the same text.
+
+** Common Lisp: The Engine of Self-Modification
+
+There is a beautiful irony to openCortex: Lisp was invented in 1958 specifically to achieve Artificial Intelligence, and it has been waiting nearly 70 years for /this exact moment/ in computing history.
+
+Lisp possesses a unique property called *Homoiconicity*: the primary representation of the program is also a data structure (nested lists) within the language itself. Because Lisp code /is/ Lisp data, it is trivially easy for an AI to generate, manipulate, and safely evaluate new tools at runtime.
+
+This makes Lisp the ultimate, un-brittle language for a "self-writing" agent. The agent doesn't need an AST parser—it can simply read and write lists directly. The agent doesn't need a code generator—it can write Lisp that executes Lisp.
+
+** The Probabilistic-Deterministic Loop
+
+openCortex does not let AI models touch your system directly. Instead, it splits cognition into two distinct engines:
+
+1. *The Probabilistic Engine (Neural/Dynamic):* Provides semantic understanding and dynamic reasoning. It utilizes a **Dynamic LLM Cascade** (OpenRouter, Ollama, Anthropic) to ensure the agent always has a "brain," falling back to local models if cloud services are unavailable.
+
+2. *The Deterministic Engine (Logic/Safety):* Intercepts LLM proposals and formally verifies them against your security rules (the "Bouncer" pattern) before execution.
+
+#+begin_src mermaid
+flowchart LR
+ subgraph Probabilistic["Probabilistic Engine (LLM)"]
+ LLM[LLM Call]
+ end
+
+ subgraph Deterministic["Deterministic Engine (Skills)"]
+ Policy[Policy Skill
Constitutional invariants]
+ Bouncer[Bouncer Skill
Security vectors]
+ Validator[Lisp Validator
Structural verification]
+ end
+
+ subgraph Actuation["Actuation"]
+ Shell[Shell Actuator]
+ TUI[TUI Client]
+ Emacs[Emacs Gateway]
+ end
+
+ LLM -->|Proposes action| Deterministic
+ Policy -->|Checks| Bouncer
+ Bouncer -->|Verifies| Validator
+ Validator -->|Approves| Actuation
+ Actuation -->|Feeds back| LLM
+#+end_src
* Architecture: Thin Harness, Fat Skills
-To guarantee long-term stability, opencortex enforces a strict architectural boundary inspired by the "thin harness, fat skills" philosophy.
+To guarantee long-term stability, openCortex enforces a strict architectural boundary inspired by the "thin harness, fat skills" philosophy.
** The Minimalist Harness
+
The Lisp microkernel is a thin, unbreakable harness strictly responsible for:
-1. *The Memory:* Maintaining the live graph of your Memex in RAM.
-2. *The Unified Envelope:* A protocol-agnostic communication layer that ensures TUI, CLI, and remote gateways (Signal, Telegram) are treated as equal citizens.
-3. *The Metabolic Cycle:* Moving signals through the Perceive -> Reason -> Act pipeline.
+
+| Layer | Responsibility | Examples |
+|-------|----------------|----------|
+| *Perceive* | Normalize sensory input | CLI parsing, Emacs events, heartbeats |
+| *Reason* | Bridge neural and deterministic | LLM dispatch, response parsing, skill routing |
+| *Act* | Execute approved actions | Shell commands, tool calls, UI output |
+| *Memory* | Live object store | Org-object graph, snapshots, rollback |
+
+What the harness does /not/ contain:
+- Policy rules (those are skills)
+- LLM integrations (those are skills)
+- Domain-specific functionality (those are skills)
** Literate, Single-File Skills
-In opencortex, a Skill is simply a *single .org file* containing everything: the documentation, the AI instructions, and the deterministic Lisp code. When the system boots, it compiles these skills directly into the live Lisp image.
-** The Anatomy: Three Data Stores
-1. *The Linguistic Substrate (Plaintext Files):* The human-readable Source of Truth on your hard drive.
-2. *The Lisp Memory (RAM):* The "Active Brain," a live, threaded graph of Lisp objects representing your Memex.
-3. *The Telemetry Store (External):* A high-volume database for sub-deterministic sensory data.
+In openCortex, a Skill is simply a *single .org file* containing everything:
+- The documentation (prose explaining the skill's purpose)
+- The AI instructions (how the LLM should use this skill)
+- The deterministic code (Lisp that verifies/proposes actions)
-** The Psychology: The 2x2 Cognitive Matrix
-| | Probabilistic (Neural/Intuitive) | Deterministic (Deterministic/Logical) |
-| :--- | :--- | :--- |
-| Foreground (Active) | *The Interface:* Fast AI models for conversation and multimodal ingestion. | *The Steward:* Lisp engine that safely retrieves data and enforces security rules. |
-| Background (Passive) | *The Editor:* Deep AI models finding patterns while you sleep. | *The Librarian:* Lisp engine maintaining data integrity and filing notes. |
+When the system boots, it compiles these skills directly into the live Lisp image. Skills are hot-reloadable without restarting the daemon.
-** The Physiology: Five Core Processes
-1. *Perception:* Automatically vectorizes your input and sets the "Foreground Focus."
-2. *Reasoning:* Uses Lisp-native logic to reconcile contradictions.
-3. *Distillation:* Background loop extracting concepts into permanent, evergreen notes (The Scribe).
-4. *Reflection:* Heartbeat-driven process maintaining structural health (The Gardener).
-5. *Sensation:* Monitors telemetry data and flags significant anomalies.
+#+begin_src mermaid
+flowchart TD
+ subgraph Skill["Skill: policy.org"]
+ Docs["Documentation
'This skill enforces...'"]
+ AI["AI Instructions
'When the user asks about...'"]
+ Code["Deterministic Code
'(defun policy-check-...)'"]
+ end
-* Quick Start (The Zero-to-One Experience)
+ subgraph Harness["Harness Core"]
+ Package["package.lisp"]
+ Loop["loop.lisp"]
+ Perceive["perceive.lisp"]
+ Reason["reason.lisp"]
+ Act["act.lisp"]
+ end
-OpenCortex can be installed and booted with a single command:
+ Code --> |Compiles into| Harness
+ Harness --> |Runs| Pipeline
+ Pipeline --> |Feeds| Skill
+#+end_src
+
+** The Metabolic Pipeline
+
+Every signal in openCortex moves through the same three-stage pipeline:
+
+1. *Perceive:* Normalize raw input into a standardized Signal
+2. *Reason:* Generate a proposal via LLM, verify via skills
+3. *Act:* Execute the approved action, generate feedback
+
+#+begin_src mermaid
+sequenceDiagram
+ participant User
+ participant Gateway
+ participant Perceive
+ participant Reason
+ participant Act
+ participant User
+
+ User->>Gateway: "Write a note about X"
+ Gateway->>Perceive: Raw message
+ Perceive->>Perceive: Normalize to Signal
+ Perceive->>Reason: Signal
+ Reason->>Reason: LLM generates proposal
+ Reason->>Reason: Skills verify proposal
+ Reason->>Act: Approved action
+ Act->>Act: Execute action
+ Act->>Reason: Feedback signal
+ Reason->>Perceive: New signal
+ Perceive->>Gateway: Response
+ Gateway->>User: "Done"
+#+end_src
+
+** The Skill Registry
+
+Skills are discovered, sorted by dependency, and loaded at boot:
+
+#+begin_src mermaid
+flowchart LR
+ subgraph Discovery["Skill Discovery"]
+ Scan["Scan skills/ directory"]
+ Sort["Topological sort by DEPENDS_ON"]
+ end
+
+ subgraph Loading["Skill Loading"]
+ Validate["Validate syntax"]
+ Jail["Jail in package namespace"]
+ Register["Register in catalog"]
+ end
+
+ Scan --> Sort --> Validate --> Jail --> Register
+#+end_src
+
+* The Three Data Stores
+
+openCortex maintains three distinct representations of your knowledge:
+
+| Store | Format | Location | Purpose |
+|-------|--------|----------|---------|
+| *Source of Truth* | Plaintext .org files | `~/memex/` | Human-readable, version-controlled |
+| *Active Brain* | RAM (Lisp hash tables) | Memory | Fast, live, queryable |
+| *Snapshots* | Binary .snap files | `~/.opencortex/` | Crash recovery, rollback |
+
+The Active Brain is built from the Source of Truth on boot and kept in sync via:
+- Buffer updates from Emacs (when you edit)
+- Heartbeat snapshots (periodic persistence)
+- Graceful shutdown saves
+
+* The Evolutionary Roadmap
+
+** v0.1.0: The Autonomous Foundation (Current Release)
+
+The initial MVP establishing a secure, auditable Lisp kernel:
+- [x] Probabilistic-Deterministic pipeline
+- [x] Skill engine with package jailing
+- [x] Policy and Bouncer security gates
+- [x] Memory persistence and snapshots
+- [x] CLI and TUI interfaces
+- [x] Literate Granularity standard
+
+** v0.2.0: Interactive Refinement
+
+Elevating the user interface:
+- [ ] Croatoan TUI with syntax highlighting
+- [ ] Interactive Lisp CLI wizard
+- [ ] Slash commands (/help, /exit, /status)
+- [ ] Skill hot-reload mechanism
+- [ ] `/doctor` environment diagnostics
+
+** v1.0.0: The Verified Wrapper (Target)
+
+Achieving feature parity with SOTA autonomous agents but with Lisp-grade mathematical security:
+- [ ] Autonomous self-editing (file I/O cognitive tools)
+- [ ] Formal verification gates for external tools
+- [ ] End-to-end autonomous engineering workflows
+- [ ] Full skill catalog (Scribe, Gardener, etc.)
+
+** v2.0.0: The Cannibalization
+
+Replacing string-based tool wrappers with native Lisp data structures:
+- [ ] DOM as native Lisp AST (Cannibalize Browser)
+- [ ] Native OS bindings (Cannibalize Shell)
+- [ ] Replace bash scripts with Lisp functions
+
+** v3.0.0: True Symbolic Determinism
+
+The great inversion:
+- [ ] LLM relegated to semantic translation layer
+- [ ] Deterministic Planner (The Solver) takes the wheel
+- [ ] Self-correcting syntax gates
+- [ ] The Memex that outlives the cloud
+
+* Quick Start
+
+** Installation
#+begin_src bash
curl -sSL https://raw.githubusercontent.com/gharbeia/opencortex/main/opencortex.sh | bash -s -- setup
#+end_src
-After installation, start interacting immediately:
+** Usage
#+begin_src bash
# Start the rich Terminal UI
@@ -76,22 +262,43 @@ opencortex tui
# Or use the raw CLI
opencortex cli
+
+# Boot without interactive session
+opencortex boot
#+end_src
-* The Evolutionary Roadmap
+* Design Principles
-** v0.1.0: The Autonomous Foundation (Current Release)
-The initial MVP establishing a secure, auditable Lisp kernel. Features a robust metabolic pipeline, mandatory skill enforcement, and background distillation.
+** 1. Radical Transparency
-** v1.0.0: The Verified Wrapper (Current Target)
-Achieving feature parity with SOTA autonomous agents but with Lisp-grade mathematical security.
-- *The Tools are External:* Standard bash shell, headless browser (Playwright), and standard file I/O.
-- *The Safety is Internal:* The Bouncer and Formal Verification gates mathematically prove actions are safe.
+If you can't explain it, you can't do it. Every action must be auditable. Hidden reasoning is forbidden.
-** v2.0.0: The Cannibalization
-Replacing string-based tool wrappers with native Lisp data structures.
-- *Cannibalizing the Browser:* Ingesting the DOM as a native Lisp AST.
-- *Cannibalizing the Shell:* Moving from bash execution to native OS API bindings.
+** 2. Autonomy First
-** v3.0.0: True Symbolic Determinism
-The great inversion. The Lisp engine takes the wheel, and the LLM is relegated to a mere semantic translation layer for the messy outside world.
+Dependency on proprietary systems is debt. Prefer local, offline-capable solutions.
+
+** 3. Zero Bloat
+
+Complexity must be earned, not anticipated. The harness must remain minimal.
+
+** 4. Modularity
+
+The kernel must survive even if all skills fail. Complexity belongs at the edges.
+
+** 5. Mentorship
+
+Teaching is the highest form of assistance. Every action should increase capability.
+
+** 6. Sustainability
+
+Build for the 100-year horizon. Design for offline operation, local inference.
+
+* Contributing
+
+See [[file:docs/CONTRIBUTING.org][CONTRIBUTING.org]] for the Literate Granularity standard and skill creation guidelines.
+
+* License
+
+openCortex is released under the [[file:LICENSE][AGPLv3 license]].
+
+See [[file:CLA.org][CLA.org]] for the Contributor License Agreement.
\ No newline at end of file
diff --git a/skills/org-skill-bouncer.org b/skills/org-skill-bouncer.org
index 78bc9d3..264a6d7 100644
--- a/skills/org-skill-bouncer.org
+++ b/skills/org-skill-bouncer.org
@@ -1,7 +1,7 @@
:PROPERTIES:
:ID: bouncer-agent-skill
:CREATED: [2026-04-11 Sat 15:20]
-:EDITED: [2026-04-13 Mon 18:35]
+:EDITED: [2026-04-22 Wed 16:00]
:END:
#+DEPENDS_ON: org-skill-credentials-vault
#+TITLE: SKILL: Deterministic Engine Bouncer (Authorization Gate)
@@ -9,149 +9,373 @@
#+FILETAGS: :system:bouncer:authorization:autonomy:
* Overview
-The *Deterministic Engine Bouncer* is the authorization gate for high-risk actions. It serializes intercepted actions into Org nodes ("Flight Plans") and re-injects them once manually approved by the Autonomous.
+
+The *Bouncer Skill* is the physical security layer of OpenCortex. While the Policy skill enforces constitutional invariants (transparency, autonomy, modularity), the Bouncer enforces operational security checks.
+
+Think of Policy as the constitution and Bouncer as the bouncer at the door:
+- **Policy** asks: "Is this action aligned with our values?"
+- **Bouncer** asks: "Is this action safe to execute?"
+
+** The Flight Plan Pattern
+
+High-risk actions don't simply pass or fail—they can enter the "Flight Plan" approval workflow:
+
+1. Bouncer intercepts a risky action
+2. Creates an Org node ("Flight Plan") describing the action
+3. User manually approves the flight plan in Emacs
+4. Bouncer detects approval on next heartbeat
+5. Action is re-injected with `approved = t` flag, bypassing the gate
+
+This creates human-in-the-loop oversight for dangerous operations without blocking the system entirely.
+
+** Why a Separate Skill?**
+
+Security and policy are separated for clarity and auditability:
+- Policy decisions can be explained (they reference invariants)
+- Bouncer decisions are technical (they reference threat vectors)
+
+When something is blocked, the logs clearly show which layer blocked it and why.
* Package Context
+
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
(in-package :opencortex)
#+end_src
-* Deep Packet Inspection (DPI)
-The Bouncer ensures the action is "safe" by inspecting the payload content via Deep Packet Inspection.
+* Security Vectors
-** Secret Exposure Check
-Retrieves all active secrets from the vault and scans the payload for potential leaks.
+The Bouncer implements the 5-Vector security model:
+
+| Vector | Threat | Response |
+|--------|--------|----------|
+| Secret Exposure | API keys, passwords in output | Hard block |
+| Network Exfiltration | Data sent to unauthorized hosts | Approval required |
+| Shell Execution | Arbitrary command execution | Approval required |
+| File Modification | Writing/deleting files | Soft check |
+| Eval Execution | Arbitrary code evaluation | Approval required |
+
+** Secret Exposure Detection
+
+The vault stores sensitive credentials. This check scans action text for vault secrets to prevent accidental exposure.
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
(defun bouncer-scan-secrets (text)
- "Returns the name of the secret found in TEXT, or NIL if clean."
+ "Scans TEXT for known secrets from the vault.
+
+ RETURNS: The name of the matched secret, or NIL if text is clean.
+
+ This prevents the catastrophic failure mode where the agent
+ accidentally echoes an API key in its response or log output.
+
+ The check uses substring matching (not regex) for reliability.
+ Only secrets longer than 5 characters are checked to avoid
+ false positives on common words."
+
(when (and text (stringp text))
+
(let ((found-secret nil))
+
(maphash (lambda (key val)
+ ;; Only check secrets of meaningful length
(when (and val (stringp val) (> (length val) 5))
+ ;; Search for secret value in action text
(when (search val text)
(setf found-secret key))))
+
opencortex::*vault-memory*)
+
found-secret)))
#+end_src
-** Network Exfiltration Check
-Inspects shell commands for unwhitelisted domains or IP addresses.
+** Network Exfiltration Detection
+
+Detects when shell commands try to send data to untrusted network destinations.
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
+(defvar *bouncer-network-whitelist*
+ '("api.telegram.org" "matrix.org" "googleapis.com" "openai.com" "anthropic.com")
+ "Domains that the Bouncer considers safe for outbound connections.
+
+ This whitelist should be minimal—only services explicitly configured
+ as gateways. All other outbound connections require approval.")
+
(defun bouncer-check-network-exfil (cmd)
- "Returns T if the command appears to target an unwhitelisted external host."
+ "Detects if CMD attempts to contact an unwhitelisted external host.
+
+ Returns T if the command targets an unknown external host.
+ Returns NIL if the command is clean or only contacts whitelisted hosts.
+
+ The check looks for HTTP/HTTPS/FTP URLs and extracts the domain.
+ If the domain isn't in *bouncer-network-whitelist*, it's flagged."
+
(when (and cmd (stringp cmd))
- ;; Basic check for common data exfiltration tools being used with IPs/URLs
- (let ((network-whitelist '("api.telegram.org" "matrix.org" "googleapis.com" "openai.com" "anthropic.com")))
- (when (cl-ppcre:scan "(http|https|ftp)://([\\w\\.-]+)" cmd)
- (multiple-value-bind (match regs)
- (cl-ppcre:scan-to-strings "(http|https|ftp)://([\\w\\.-]+)" cmd)
- (declare (ignore match))
- (let ((domain (aref regs 1)))
- (not (some (lambda (safe) (search safe domain)) network-whitelist))))))))
+
+ ;; Look for URL patterns in the command
+ (when (cl-ppcre:scan "(http|https|ftp)://([\\w\\.-]+)" cmd)
+
+ (multiple-value-bind (match regs)
+ (cl-ppcre:scan-to-strings "(http|https|ftp)://([\\w\\.-]+)" cmd)
+
+ (declare (ignore match))
+
+ (let ((domain (aref regs 1)))
+
+ ;; Check if domain is whitelisted
+ (not (some (lambda (safe) (search safe domain))
+ *bouncer-network-whitelist*)))))))
#+end_src
-* Runtime Guard (bouncer-check)
-The primary entry point for all high-impact actions. It blocks or queues actions based on risk vectors.
+* Runtime Guard
+
+** bouncer-check: Main Security Gate
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
(defun bouncer-check (action context)
- "The 5-Vector security gate. Blocks or queues actions based on risk."
+ "The 5-Vector security gate for high-risk actions.
+
+ Evaluates an action against all security vectors and either:
+ - Returns the action unchanged (pass)
+ - Returns a blocking LOG event (hard block)
+ - Returns an approval-required EVENT (soft block)
+
+ Vector evaluation order:
+ 1. Already approved actions pass immediately
+ 2. Secret exposure → hard block
+ 3. Network exfiltration → approval required
+ 4. High-impact targets → approval required
+
+ The context parameter is not used directly but provided for
+ consistency with the skill gate signature."
+
+ (declare (ignore context))
+
(let* ((target (getf action :target))
(payload (getf action :payload))
(text (or (getf payload :text) (getf action :text)))
;; Extract cmd from direct shell or tool-mediated shell call
(cmd (or (getf payload :cmd)
- (when (and (eq target :tool) (equal (getf payload :tool) "shell"))
- (getf (getf payload :args) :cmd))))
+ (when (and (eq target :tool)
+ (equal (getf payload :tool) "shell"))
+ (getf (getf payload :args) :cmd))))
(approved (getf action :approved)))
-
- (cond
- ;; 0. Bypass for already approved actions
- (approved action)
- ;; 1. Secret Exposure Vector (Hard Block)
+ (cond
+
+ ;; Vector 0: Already approved actions pass through
+ (approved
+ action)
+
+ ;; Vector 1: Secret Exposure (Hard Block)
+ ;; If any vault secret is found in the action text, block immediately
((and text (bouncer-scan-secrets text))
(let ((secret-name (bouncer-scan-secrets text)))
- (harness-log "SECURITY VIOLATION: Blocked leak of secret ~a" secret-name)
- `(:type :log :payload (:level :error :text ,(format nil "Action blocked: Potential exposure of ~a" secret-name)))))
+ (harness-log "SECURITY VIOLATION: Blocked potential leak of secret '~a'" secret-name)
+ (list :type :LOG
+ :payload (list :level :error
+ :text (format nil "Action blocked: Potential exposure of '~a'" secret-name)))))
- ;; 2. Network Exfiltration Vector (Authorization Required)
- ((and (or (eq target :shell)
- (and (eq target :tool) (equal (getf payload :tool) "shell")))
+ ;; Vector 2: Network Exfiltration (Soft Block)
+ ;; Shell commands targeting unknown hosts require approval
+ ((and (or (eq target :shell)
+ (and (eq target :tool)
+ (equal (getf payload :tool) "shell")))
(bouncer-check-network-exfil cmd))
+
(harness-log "SECURITY WARNING: External network call detected. Queuing for approval.")
- `(:type :EVENT :payload (:sensor :approval-required :action ,action)))
- ;; 3. High-Impact Target Vector (Authorization Required)
+ (list :type :EVENT
+ :payload (list :sensor :approval-required
+ :action action)))
+
+ ;; Vector 3: High-Impact Targets (Soft Block)
+ ;; Shell execution, file repair, and eval require approval
((or (member target '(:shell))
- (and (eq target :tool) (member (getf payload :tool) '("shell" "repair-file") :test #'string=))
- (and (eq target :EMACS) (eq (getf payload :action) :eval)))
- (harness-log "SECURITY: High-impact action ~a requires approval." (or (getf payload :tool) target))
- `(:type :EVENT :payload (:sensor :approval-required :action ,action)))
+ (and (eq target :tool)
+ (member (getf payload :tool) '("shell" "repair-file") :test #'string=))
+ (and (eq target :emacs)
+ (eq (getf payload :action) :eval)))
- ;; 4. Default Pass
- (t action))))
+ (harness-log "SECURITY: High-impact action requires approval: ~a"
+ (or (getf payload :tool) target))
+
+ (list :type :EVENT
+ :payload (list :sensor :approval-required
+ :action action)))
+
+ ;; Vector 4: Default pass
+ (t
+ action))))
#+end_src
-* Approval Processing
-The Bouncer periodically scans the Memex for approved "Flight Plans" and re-injects them into the metabolic loop.
+* Flight Plan Workflow
+
+** Processing Approvals
+
+When a flight plan is approved in Emacs, the Bouncer detects it and re-injects the action.
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
(defun bouncer-process-approvals ()
- "Scans the object store for APPROVED flight plans and re-injects their actions."
+ "Scans the object store for APPROVED flight plans and re-injects them.
+
+ This function is called on every heartbeat, allowing the agent to
+ check for approvals without blocking the main signal pipeline.
+
+ Flight Plan format:
+ - Has TAGS including \"FLIGHT_PLAN\"
+ - Has TODO set to \"APPROVED\"
+ - Has ACTION containing the serialized action plist
+
+ When an approved flight plan is found:
+ 1. Deserialize the action from the ACTION attribute
+ 2. Mark the action as :approved = t (bypasses security gate)
+ 3. Re-inject into the signal pipeline
+ 4. Mark the flight plan as DONE
+
+ Returns T if any flight plans were processed."
+
(let ((approved-nodes (list-objects-with-attribute :TODO "APPROVED"))
(found-any nil))
+
(dolist (node approved-nodes)
+
(let* ((tags (getf (org-object-attributes node) :TAGS))
(action-str (getf (org-object-attributes node) :ACTION)))
- (when (and (member "FLIGHT_PLAN" tags :test #'string-equal) action-str)
- (harness-log "BOUNCER: Found approved flight plan ~a. Re-injecting..." (org-object-id node))
+
+ ;; Only process flight plans (not other APPROVED items)
+ (when (and (member "FLIGHT_PLAN" tags :test #'string-equal)
+ action-str)
+
+ (harness-log "BOUNCER: Found approved flight plan '~a'. Re-injecting..."
+ (org-object-id node))
+
(let ((action (ignore-errors (read-from-string action-str))))
(when action
- ;; Mark as approved to bypass the gate
+
+ ;; Mark as approved to bypass the security gate on re-injection
(setf (getf action :approved) t)
+
+ ;; Re-inject the action into the signal pipeline
(inject-stimulus action)
- ;; Mark as DONE
+
+ ;; Mark the flight plan as done
(setf (getf (org-object-attributes node) :TODO) "DONE")
+
(setq found-any t))))))
+
found-any))
#+end_src
-* Skill Definition
-The Bouncer skill reacts to approval requirements by creating flight plan nodes, and periodically checks for manual approvals via heartbeats.
+** Creating Flight Plans
+
+When the Bouncer intercepts a high-risk action, it creates a flight plan node for manual approval.
+
+#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
+(defun bouncer-create-flight-plan (blocked-action)
+ "Creates an Org node representing a pending flight plan for manual approval.
+
+ BLOCKED-ACTION is the action plist that was intercepted.
+
+ The flight plan node contains:
+ - A title describing the action
+ - TODO set to PLAN (awaiting approval)
+ - TAGS including FLIGHT_PLAN
+ - ACTION attribute containing the serialized action
+
+ The user reviews the flight plan and changes TODO to APPROVED.
+ On the next heartbeat, bouncer-process-approvals will detect
+ the approval and re-inject the action.
+
+ Returns the generated org-id for the flight plan."
+
+ (let ((id (org-id-new)))
+ (harness-log "BOUNCER: Creating flight plan node '~a'..." id)
+
+ ;; Inject a node creation request
+ (list :type :REQUEST
+ :target :emacs
+ :payload (list :action :insert-node
+ :id id
+ :attributes (list
+ :TITLE "Flight Plan: High-Risk Action"
+ :TODO "PLAN"
+ :TAGS '("FLIGHT_PLAN")
+ :ACTION (format nil "~s" blocked-action)))))
+#+end_src
+
+* Skill Gate
+
+** Main Gate Function
-** Skill Logic
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
(defun bouncer-deterministic-gate (action context)
- "Main gate for the bouncer skill."
+ "Main deterministic gate for the Bouncer skill.
+
+ Handles three types of signals:
+ 1. :approval-required - Create a flight plan for the blocked action
+ 2. :heartbeat - Process any pending approvals
+ 3. otherwise - Run security check on the action
+
+ The trigger is always true (bouncer evaluates all actions)
+ because security cannot be selective."
+
(let* ((payload (getf context :payload))
(sensor (getf payload :sensor)))
+
(case sensor
+
+ ;; Signal type 1: Action was blocked, create flight plan
(:approval-required
- (let* ((blocked-action (getf payload :action))
- (id (org-id-new)))
- (harness-log "BOUNCER: Creating flight plan node...")
- ;; Create the node in Emacs (or inbox)
- (list :type :REQUEST :target :EMACS :action :insert-node
- :id id :attributes `(:TITLE "Flight Plan: High-Risk Action"
- :TODO "PLAN"
- :TAGS ("FLIGHT_PLAN")
- :ACTION ,(format nil "~s" blocked-action)))))
+ (let* ((blocked-action (getf payload :action)))
+ (bouncer-create-flight-plan blocked-action)))
+
+ ;; Signal type 2: Heartbeat, check for approvals
(:heartbeat
- ;; Periodically check for approvals
(bouncer-process-approvals)
- (if action (bouncer-check action context) action))
+ ;; After processing approvals, still run the security check
+ (if action
+ (bouncer-check action context)
+ action))
+
+ ;; Signal type 3: Normal action, run security check
(otherwise
- (if action (bouncer-check action context) action)))))
+ (if action
+ (bouncer-check action context)
+ action)))))
#+end_src
** Skill Registration
+
#+begin_src lisp :tangle ../library/gen/org-skill-bouncer.lisp
(defskill :skill-bouncer
:priority 150
- :trigger (lambda (ctx) t) ;; Bouncer evaluates all actions deterministically
+ :trigger (lambda (ctx) (declare (ignore ctx)) t)
:probabilistic nil
:deterministic #'bouncer-deterministic-gate)
#+end_src
+
+* Quick Reference
+
+** Security Vectors Summary
+
+| Vector | Check | Response |
+|--------|-------|----------|
+| Secret Exposure | `bouncer-scan-secrets` | Hard block |
+| Network Exfil | `bouncer-check-network-exfil` | Approval required |
+| Shell Execution | target = :shell or tool = "shell" | Approval required |
+| Eval Execution | target = :emacs and action = :eval | Approval required |
+| File Repair | tool = "repair-file" | Approval required |
+
+** Flight Plan Lifecycle
+
+1. High-risk action intercepted → `:approval-required` signal
+2. Flight plan node created in Emacs with `TODO: PLAN`
+3. User reviews and sets `TODO: APPROVED`
+4. Next heartbeat detects approval
+5. Action re-injected with `approved = t`
+6. Security gate bypassed, action executes
+7. Flight plan marked `TODO: DONE`
+
+* See Also
+- [[file:org-skill-credentials-vault.org][Credentials Vault]] - Where secrets are stored
+- [[file:org-skill-policy.org][Policy Skill]] - Constitutional constraints
+- [[file:../harness/act.org][Act Stage]] - Where gates are invoked
\ No newline at end of file
diff --git a/skills/org-skill-policy.org b/skills/org-skill-policy.org
index dd82973..2eb466e 100644
--- a/skills/org-skill-policy.org
+++ b/skills/org-skill-policy.org
@@ -1,33 +1,65 @@
:PROPERTIES:
:ID: 47425a43-2be0-423c-8509-22592cfe9c9e
:CREATED: [2026-04-07 Tue 12:57]
-:EDITED: [2026-04-22 Wed 11:45]
+:EDITED: [2026-04-22 Wed 16:00]
:END:
#+TITLE: SKILL: System Policy
#+STARTUP: content
#+FILETAGS: :platform:policy:alignment:autonomy:
* Overview
-The *opencortex* is a probabilistic-deterministic harness for a personal operating system. It uses Org-mode as its native memory and Common Lisp as its deterministic reasoning engine.
-This skill defines the *Core System Policy*: a set of non-negotiable philosophical and technical constraints that every agentic action MUST satisfy. Unlike a passive manifesto, these invariants are enforced by the Deterministic Engine at the last mile before actuation.
+The *Policy Skill* is the constitutional law of OpenCortex. It defines the non-negotiable constraints that every agentic action must satisfy before reaching the actuator layer.
+
+Unlike a passive manifesto, Policy is *enforced* by the Deterministic Engine. The LLM proposes; Policy verifies. If an action violates an invariant, Policy blocks it and returns an auditable explanation.
+
+** Why a Constitutional Approach?**
+
+AIs fail in two ways:
+1. *Underconstraint* - They do harmful things because no one told them not to
+2. *Overconstraint* - They refuse to act because every action triggers a warning
+
+OpenCortex solves this with a *hierarchy of invariants*:
+- Some invariants block absolutely (Transparency, Modularity)
+- Others warn but don't block (Autonomy debt, Sustainability debt)
+
+This allows the agent to be both *safe* and *usable*.
+
+** The Philosophical Foundation
+
+OpenCortex is not just software—it's a *personal operating system* designed for the 100-year horizon. The Memex must outlive:
+- Cloud services that get discontinued
+- Programming languages that fall out of fashion
+- Hardware platforms that become obsolete
+
+Therefore, Policy encodes not just rules, but *values*:
+- Radical Transparency → Auditability is non-negotiable
+- Autonomy → Dependency on proprietary systems is debt, not strength
+- Zero-Bloat → Complexity is cost, not feature
+- Modularity → The kernel must survive even if all skills fail
+- Mentorship → Teaching is the highest form of assistance
+- Sustainability → Offline capability is a feature, not a limitation
* Package Context
-Every skill executes within its own jailed package namespace, while inheriting core harness symbols.
+
+Every skill executes within its own jailed package namespace, inheriting core harness symbols while maintaining isolation from other skills.
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
(in-package :opencortex)
#+end_src
* The Override Hierarchy
+
When two invariants conflict, resolution follows a strict priority order. This prevents the agent from freezing on ethical edge cases.
-1. *Radical Transparency* — An action that cannot be explained to the user is never permissible, even if it is technically optimal.
-2. *Autonomy* — Independence from proprietary control is the primary goal, but it must be achieved transparently.
-3. *Zero-Bloat* — Complexity must be justified, but a transparent, autonomous system may still be complex if the complexity is locally justified.
-4. *Modularity* — The system's kernel must remain minimal; complexity must live at the edges, not in the core. This takes precedence over mentorship when the proposed change would fatten the harness.
-5. *Mentorship* — The agent must teach, but teaching is secondary to delivering a working, transparent system.
-6. *Long-Term Sustainability* — Energy efficiency and offline capability are desired properties, not absolute blockers.
+| Priority | Invariant | Philosophy |
+|----------|-----------|------------|
+| 500 | Transparency | If you can't explain it, you can't do it |
+| 400 | Autonomy | Independence from proprietary control is the primary goal |
+| 300 | Zero-Bloat | Complexity must be earned, not imported |
+| 250 | Modularity | Complexity belongs at the edges, not the core |
+| 200 | Mentorship | Teaching increases capability; doing removes it |
+| 100 | Sustainability | Offline capability today enables 100-year survival |
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
(defvar *policy-invariant-priorities*
@@ -38,29 +70,55 @@ When two invariants conflict, resolution follows a strict priority order. This p
(:mentorship . 200)
(:sustainability . 100))
"Priority alist for policy invariant conflict resolution.
-Higher numbers take precedence.")
+Higher numbers take precedence.
+
+When two invariants conflict, the higher priority wins.
+Example: Modularity (250) takes precedence over Mentorship (200),
+meaning a change that would fatten the harness is blocked
+even if it would be educational.")
#+end_src
* The Core Invariants
** 1. Radical Transparency
-The agent's "Thought Stream" must be fully auditable. Hidden reasoning or obfuscated logic is a violation of the system's design principles. At the action gate, this means every action directed at the user MUST carry an explanation, and every action MUST be a valid, inspectable data structure.
+
+*The maxim: "If you can't explain it, you can't do it."*
+
+The agent's Thought Stream must be fully auditable. Hidden reasoning or obfuscated logic violates the system's core purpose: a transparent, comprehensible AI assistant.
+
+At the gate:
+- Every action must be a valid, inspectable data structure
+- Every user-facing action must carry an `:explanation`
+- Log messages must include the triggering invariant
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
(defun policy-check-transparency (action context)
"Ensures the action is inspectable and user-facing actions carry an explanation.
-Returns the action if clean, or a blocking LOG event if the action is opaque."
+
+ TRANSPARENCY CHECK:
+ 1. Action must be a valid plist (not opaque data)
+ 2. User-facing actions (:cli, :tui, :emacs) must include :explanation
+ 3. Heartbeat and handshake messages are exempt (they're system status)
+
+ Returns the action if clean, or a blocking LOG event if violated."
+
(declare (ignore context))
+
+ ;; Check 1: Action must be a valid plist
(unless (listp action)
(return-from policy-check-transparency
(list :type :LOG
:payload (list :level :error
:text "POLICY [Transparency]: Action is not a valid plist. Rejected."))))
+
(let* ((payload (getf action :payload))
(target (or (getf action :target) (getf action :TARGET)))
- (explanation (or (getf payload :explanation) (getf payload :EXPLANATION)
- (getf payload :rationale) (getf payload :RATIONALE))))
- ;; User-facing actions (CLI, TUI, Emacs) must explain themselves
+ (explanation (or (getf payload :explanation)
+ (getf payload :EXPLANATION)
+ (getf payload :rationale)
+ (getf payload :RATIONALE))))
+
+ ;; Check 2: User-facing actions require explanation
(when (and (member target '(:cli :tui :emacs :EMACS :CLI :TUI))
(not explanation)
(not (member (getf payload :action)
@@ -68,235 +126,427 @@ Returns the action if clean, or a blocking LOG event if the action is opaque."
(return-from policy-check-transparency
(list :type :LOG
:payload (list :level :error
- :text "POLICY [Transparency]: User-facing action missing :explanation. Blocked."))))
- action))
+ :text "POLICY [Transparency]: User-facing action missing :explanation. Blocked.")))))
+
+ action)
#+end_src
** 2. Autonomy Above All
-Every action must increase the user's independence from centralized, proprietary platforms. If a tool or library introduces a dependency on a non-autonomous entity, it must be flagged for replacement. The gate scans shell commands and tool payloads for known proprietary domains and logs a warning. It does NOT block by default, because the system itself uses gateway bridges (e.g., Telegram, Signal) as tactical concessions toward strategic autonomy.
+
+*The maxim: "Every dependency is debt."*
+
+Every action should increase the user's independence from centralized, proprietary platforms. When the system uses a proprietary API, it's logged as "autonomy debt"—acceptable tactically, but flagged for eventual replacement.
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
(defvar *proprietary-domain-watchlist*
'("googleapis.com" "api.openai.com" "anthropic.com" "api.groq.com" "openrouter.ai")
- "Domains that represent centralized, proprietary control.
-Actions targeting these are logged as autonomy debt, not hard-blocked,
-because tactical gateway usage is permitted under the strategic mandate.")
+ "Domains representing centralized, proprietary control.
+
+ Actions targeting these are logged as autonomy debt, not hard-blocked.
+ This is because tactical gateway usage (Telegram, Signal, OpenRouter)
+ is permitted under the strategic mandate for autonomy.
+
+ Strategic goal: Replace all proprietary APIs with local alternatives.
+ Tactical reality: Use what's available while building toward that goal.")
(defun policy-scan-proprietary-references (action)
"Scans ACTION text fields for proprietary domain references.
-Returns the first matched domain, or NIL if clean."
+
+ Searches in:
+ - :text and :TEXT in payload
+ - :cmd and :CMD in payload
+ - :cmd in args (for shell tool calls)
+
+ Returns the first matched domain, or NIL if clean."
+
(let* ((payload (getf action :payload))
(text (or (getf payload :text) (getf payload :TEXT) ""))
- (cmd (or (getf payload :cmd) (getf payload :CMD)
- (when (equal (getf payload :tool) "shell")
- (getf (getf payload :args) :cmd))
- ""))
+ (cmd (or (getf payload :cmd)
+ (getf payload :CMD)
+ (when (equal (getf payload :tool) "shell")
+ (getf (getf payload :args) :cmd))
+ ""))
(haystack (concatenate 'string text cmd)))
+
(dolist (domain *proprietary-domain-watchlist* nil)
(when (search domain haystack)
(return domain)))))
(defun policy-check-autonomy (action context)
- "Flags actions that reference proprietary domains. Returns the action
-with an autonomy debt log appended, or the action itself if clean."
+ "Flags actions that reference proprietary domains.
+
+ Does NOT block the action—this is a warning, not a veto.
+ The agent can use proprietary services tactically, but must
+ be aware that each usage is a step away from full autonomy.
+
+ Returns a warning LOG if proprietary reference detected,
+ or the original action if clean."
+
(declare (ignore context))
+
(let ((domain (policy-scan-proprietary-references action)))
+
(if domain
(progn
(harness-log "POLICY [Autonomy]: Detected proprietary reference '~a'. Flagged for replacement." domain)
- ;; Return a side-effect log but DO NOT block the action
+ ;; Return a warning log but DO NOT block the action
(list :type :LOG
:payload (list :level :warn
:text (format nil "Autonomy Debt: Action references proprietary domain '~a'. Consider a local alternative." domain)
:original-action action)))
- action)))
+
+ action))
#+end_src
** 3. Zero-Bloat Mandate
-The system harness must remain minimalist. "Just-in-case" code is a security vulnerability. Complexity must be earned, not imported. This invariant is enforced primarily at skill-load time (see `validate-lisp-syntax` and skill telemetry). At the action gate, it performs a lightweight size check on proposed `:create-skill` actions and warns if the payload exceeds a reasonable threshold.
+
+*The maxim: "Complexity is cost, not feature."*
+
+The system harness must remain minimalist. "Just-in-case" code is a security vulnerability. Complexity must be earned through demonstrated need, not anticipation of future use.
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
(defvar *policy-max-skill-size-chars* 50000
- "Maximum recommended size for a skill file tangled from an Org note.")
+ "Maximum recommended size for a skill file tangled from an Org note.
+
+ This is a soft limit—the check warns but does not block.
+ A large, well-documented skill is acceptable; a small, poorly-documented
+ one that adds unnecessary complexity is not.")
(defun policy-check-bloat (action context)
"Warns if a :create-skill action exceeds the bloat threshold.
-Does not block, because size alone is not a proof of complexity."
+
+ Size alone is not proof of complexity—a 50KB skill that's well-designed
+ is better than a 5KB skill that's spaghetti. This check flags for review,
+ not automatic rejection.
+
+ Returns a warning LOG if threshold exceeded, or original action if clean."
+
(declare (ignore context))
+
(let* ((payload (getf action :payload))
(act (getf payload :action))
(content (getf payload :content)))
+
(when (and (eq act :create-skill)
(stringp content)
(> (length content) *policy-max-skill-size-chars*))
+
(harness-log "POLICY [Bloat]: Proposed skill is ~a chars. Exceeds ~a char threshold."
(length content) *policy-max-skill-size-chars*)
+
(return-from policy-check-bloat
(list :type :LOG
:payload (list :level :warn
:text (format nil "Bloat Warning: Proposed skill (~a chars) exceeds ~a char threshold. Review for earned complexity."
- (length content) *policy-max-skill-size-chars*)
+ (length content) *policy-max-skill-size-chars*)
:original-action action))))
- action))
+
+ action)
#+end_src
-** 4. Technical Mastery & Mentorship
-The agent's goal is not to "do it for the user," but to "empower the user." Every autonomous action must be explained at a level that increases the user's technical understanding of the Lisp Machine. At the gate, this means that any action which performs a non-trivial side-effect (file write, shell execution, skill reload) MUST include a `:mentorship-note` explaining *what* was done and *why*.
+** 4. Modularity
-#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
-(defvar *mentorship-required-actions*
- '(:create-skill :eval :modify-file :write-file :replace :rename-file :delete-file :shell :create-note)
- "Actions that trigger the Mentorship invariant.")
+*The maxim: "The kernel must survive even if all skills fail."*
-(defun policy-check-mentorship (action context)
- "Blocks high-impact actions that lack a mentorship note."
- (declare (ignore context))
- (let* ((payload (getf action :payload))
- (act (or (getf payload :action) (getf action :action)))
- (note (or (getf payload :mentorship-note) (getf payload :MENTORSHIP-NOTE)))
- (target (or (getf action :target) (getf action :TARGET)))
- (tool (when (eq target :tool) (getf payload :tool))))
- (when (or (member act *mentorship-required-actions*)
- (member tool '("shell" "eval" "repair-file")))
- (unless note
- (return-from policy-check-mentorship
- (list :type :LOG
- :payload (list :level :error
- :text "POLICY [Mentorship]: High-impact action missing :mentorship-note. Explain what you are doing and why. Blocked.")))))
- action))
-#+end_src
+Every system should be decomposed into a minimal, unbreakable core and hot-swappable capabilities. Complexity must live at the edges, never in the kernel.
-** 5. Long-Term Sustainability
-Prioritize local, energy-efficient, and offline-first architectures. The "Memex" should be functional on a 100-year horizon. At the gate, this means we log a sustainability debt event whenever the probabilistic engine falls back to a remote cloud provider because a local model (e.g., Ollama) is unavailable.
-
-#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
-(defvar *cloud-only-backends* '(:openrouter :openai :anthropic :groq :gemini-api)
- "Backends that require an internet connection and external infrastructure.")
-
-(defun policy-check-sustainability (action context)
- "Logs sustainability debt when the action relies on cloud-only infrastructure.
-Does not block, because tactical cloud usage is permitted."
- (let* ((payload (getf context :payload))
- (backend (getf payload :backend))
- (provider (getf payload :provider)))
- (when (or (member backend *cloud-only-backends*)
- (member provider *cloud-only-backends*))
- (harness-log "POLICY [Sustainability]: Cloud provider '~a' used. Logged as sustainability debt."
- (or backend provider))
- (return-from policy-check-sustainability
- (list :type :LOG
- :payload (list :level :warn
- :text (format nil "Sustainability Debt: Reliance on cloud provider '~a'. Consider Ollama or local inference."
- (or backend provider))))))
- action))
-#+end_src
-
-** 6. Modularity
-Every system should be decomposed into a minimal, unbreakable core and hot-swappable capabilities. Complexity must live at the edges, never in the kernel. At the gate, this means any proposed modification to the protected core must carry a `:modularity-justification` explaining why the change cannot be implemented as a skill.
+This is the most important invariant for system stability. If the harness grows fat, it becomes:
+- Harder to verify for security
+- Harder to debug when things go wrong
+- Harder to maintain across versions
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
(defvar *modularity-protected-paths*
'("harness/" "opencortex.asd")
"Paths that constitute the unbreakable core of the system.
-Any action targeting these paths must include a :modularity-justification.
-This list is project-specific and should be configured at boot time.")
+
+ Any action targeting these paths must include a :modularity-justification
+ explaining why the change cannot be implemented as a skill.
+
+ The Thin Harness principle: What belongs in the harness?
+ - Core signal processing (Perceive-Reason-Act loop)
+ - Memory and persistence primitives
+ - Protocol definition and validation
+ - Skills register and dispatch
+
+ What belongs in skills?
+ - Policy and security
+ - LLM integration
+ - Domain-specific functionality
+ - New actuators")
(defun policy-check-modularity (action context)
- "Blocks modifications to the system's protected core unless justified."
+ "Blocks modifications to the system's protected core unless justified.
+
+ MODULARITY CHECK:
+ 1. If the action targets a protected path
+ 2. And no :modularity-justification is provided
+ 3. Then block with an explanation
+
+ The justification should explain WHY the change cannot be a skill.
+ Common valid reasons:
+ - The change fixes a bug in the harness itself
+ - The change adds a primitive that skills cannot implement
+ - The change is required for security hardening
+
+ Invalid reasons:
+ - 'It's easier to modify the harness'
+ - 'Skills are too slow'
+ - 'I want to keep it all in one place'"
+
(declare (ignore context))
+
(let* ((payload (getf action :payload))
- (target-file (or (getf payload :file) (getf payload :filename)))
+ (target-file (or (getf payload :file)
+ (getf payload :filename)))
(justification (or (getf payload :modularity-justification)
(getf payload :MODULARITY-JUSTIFICATION))))
+
(when (and target-file
- (some (lambda (path) (search path target-file)) *modularity-protected-paths*)
+ (some (lambda (path) (search path target-file))
+ *modularity-protected-paths*)
(not justification))
+
(return-from policy-check-modularity
(list :type :LOG
:payload (list :level :error
:text "POLICY [Modularity]: Modification to protected core path blocked. Provide :modularity-justification explaining why this cannot be a skill."
:blocked-path target-file))))
- action))
+
+ action)
#+end_src
-* The Policy Explanation Engine
-When the policy gate modifies or blocks an action, it must tell the user *why*. This function formats a human-readable rationale from the invariant that triggered the interception.
+** 5. Technical Mastery & Mentorship
+
+*The maxim: "Teaching is the highest form of assistance."*
+
+The agent's goal is not to "do it for the user," but to "empower the user." Every autonomous action must be explained at a level that increases the user's technical understanding.
+
+#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
+(defvar *mentorship-required-actions*
+ '(:create-skill :eval :modify-file :write-file :replace
+ :rename-file :delete-file :shell :create-note)
+ "Actions that trigger the Mentorship invariant.
+
+ These are high-impact actions that should come with explanations
+ not just for the user, but for future debugging and maintenance.")
+
+(defun policy-check-mentorship (action context)
+ "Blocks high-impact actions that lack a mentorship note.
+
+ MENTORSHIP CHECK:
+ 1. If the action is in *mentorship-required-actions*
+ 2. Or if the action calls shell/eval/repair-file tools
+ 3. Then require :mentorship-note explaining what and why
+
+ The mentorship note should be:
+ - Concise (1-2 sentences)
+ - Educational (explain the principle, not just the action)
+ - Actionable (help the user understand the outcome)"
+
+ (declare (ignore context))
+
+ (let* ((payload (getf action :payload))
+ (act (or (getf payload :action)
+ (getf action :action)))
+ (note (or (getf payload :mentorship-note)
+ (getf payload :MENTORSHIP-NOTE)))
+ (target (or (getf action :target)
+ (getf action :TARGET)))
+ (tool (when (eq target :tool)
+ (getf payload :tool))))
+
+ (when (or (member act *mentorship-required-actions*)
+ (member tool '("shell" "eval" "repair-file")))
+
+ (unless note
+ (return-from policy-check-mentorship
+ (list :type :LOG
+ :payload (list :level :error
+ :text "POLICY [Mentorship]: High-impact action missing :mentorship-note. Explain what you are doing and why. Blocked.")))))
+
+ action)
+#+end_src
+
+** 6. Long-Term Sustainability
+
+*The maxim: "Build for the 100-year horizon."*
+
+The Memex should be functional even when:
+- Internet is unavailable
+- Cloud services are discontinued
+- Hardware platforms change
+
+This means preferring local, energy-efficient architectures over cloud-dependent ones.
+
+#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
+(defvar *cloud-only-backends* '(:openrouter :openai :anthropic :groq :gemini-api)
+ "Backends requiring internet connection and external infrastructure.
+
+ These are acceptable as fallbacks when local inference is unavailable,
+ but should be logged as sustainability debt for tracking purposes.")
+
+(defun policy-check-sustainability (action context)
+ "Logs sustainability debt when action relies on cloud-only infrastructure.
+
+ Does NOT block—this is informational, not prohibitive.
+ Cloud usage is acceptable tactically (when local models fail),
+ but every cloud usage should be a conscious decision, not a default."
+
+ (let* ((payload (getf context :payload))
+ (backend (getf payload :backend))
+ (provider (getf payload :provider))
+
+ (when (or (member backend *cloud-only-backends*)
+ (member provider *cloud-only-backends*))
+
+ (harness-log "POLICY [Sustainability]: Cloud provider '~a' used. Logged as sustainability debt."
+ (or backend provider))
+
+ (return-from policy-check-sustainability
+ (list :type :LOG
+ :payload (list :level :warn
+ :text (format nil "Sustainability Debt: Reliance on cloud provider '~a'. Consider Ollama or local inference."
+ (or backend provider))))))
+
+ action)
+#+end_src
+
+* Policy Explanation Engine
+
+When the policy gate blocks or modifies an action, it must tell the user *why*. This creates an auditable log of every policy decision.
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
(defun policy-explain (invariant-key message &optional original-action)
"Formats a policy decision into an auditable explanation plist.
-INVARIANT-KEY is one of :transparency, :autonomy, :bloat, :modularity, :mentorship, :sustainability.
-MESSAGE is a human-readable string.
-ORIGINAL-ACTION is the action that was blocked or modified."
+
+ INVARIANT-KEY is one of:
+ :transparency, :autonomy, :bloat, :modularity, :mentorship, :sustainability
+
+ MESSAGE is a human-readable string explaining the decision.
+
+ ORIGINAL-ACTION is the action that was blocked or modified.
+
+ Returns a REQUEST plist addressed to the original source,
+ containing the explanation and original action for transparency."
+
(list :type :REQUEST
- :target (or (ignore-errors (getf (getf original-action :meta) :source)) :cli)
+ :target (or (ignore-errors
+ (getf (getf original-action :meta) :source))
+ :cli)
:payload (list :action :message
:text (format nil "[POLICY ~a] ~a" invariant-key message)
- :explanation (format nil "Invariant: ~a | Rationale: ~a" invariant-key message)
+ :explanation (format nil "Invariant: ~a | Rationale: ~a"
+ invariant-key message)
:original-action original-action)))
#+end_src
* The Policy Gate
-The main deterministic entry point for the policy skill. It runs invariant checks in priority order. If a check returns a blocking LOG event, the gate immediately yields with an explanation. If a check returns a modified action (e.g., a warning wrapper), the modified action is passed down the chain.
-The gate also attempts to delegate to Engineering Standards, but it does so robustly: it searches multiple candidate package names and falls back gracefully if the standards skill is not loaded.
+** Running Invariant Checks
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
(defun policy-run-invariant-checks (action context)
- "Runs all invariant checks in priority order. Returns the final action,
-a blocking LOG event, or a warning wrapper."
+ "Runs all invariant checks in priority order.
+
+ Priority order (from *policy-invariant-priorities*):
+ 1. Transparency (500) - blocks non-transparent actions
+ 2. Autonomy (400) - warns on proprietary dependencies
+ 3. Bloat (300) - warns on oversized skills
+ 4. Modularity (250) - blocks unprotected core modifications
+ 5. Mentorship (200) - blocks unexplained high-impact actions
+ 6. Sustainability (100) - warns on cloud dependencies
+
+ Returns:
+ - The final action (possibly modified by checks)
+ - A blocking LOG event (if any check returned :error level)
+ - A warning wrapper (if checks returned :warn level but no blocks)"
+
(let ((checks '(policy-check-transparency
policy-check-autonomy
policy-check-bloat
policy-check-modularity
policy-check-mentorship
policy-check-sustainability)))
+
(dolist (check-fn checks action)
(let ((result (funcall check-fn action context)))
- ;; If the check returned a LOG event, treat it as a block/warning
+
+ ;; If the check returned a LOG/EVENT, interpret it
(when (and (listp result)
(member (getf result :type) '(:LOG :EVENT)))
- (let ((level (getf (getf result :payload) :level)))
- (cond ((eq level :error)
- ;; Hard block: return the log event directly
- (return-from policy-run-invariant-checks result))
- (t
- ;; Warning: log it, but continue with the original action
- (harness-log "~a" (getf (getf result :payload) :text))))))))))
+ (let ((level (getf (getf result :payload) :level)))
+
+ (cond
+ ;; Hard block: error level stops processing immediately
+ ((eq level :error)
+ (return-from policy-run-invariant-checks result))
+
+ ;; Soft warning: log but continue with original action
+ (t
+ (harness-log "~a" (getf (getf result :payload) :text)))))))))
+
+ action)
+#+end_src
+
+** Finding Engineering Standards
+
+#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
(defun policy-find-engineering-standards-gate ()
"Searches for the Engineering Standards gate across known jailed package names.
-Returns the function symbol, or NIL if unavailable."
+
+ The standards skill may be in opencortex-contrib submodule,
+ so we search multiple possible package names with graceful fallback.
+
+ Returns the function symbol, or NIL if unavailable."
+
(dolist (pkg-name '(:opencortex.skills.org-skill-engineering-standards
:opencortex.skills.org-skill-engineering
:opencortex.skills.engineering-standards)
nil)
+
(let ((pkg (find-package pkg-name)))
(when pkg
(let ((sym (find-symbol "ENGINEERING-STANDARDS-GATE" pkg)))
(when (and sym (fboundp sym))
(return (symbol-function sym))))))))
+#+end_src
+** Main Policy Gate
+
+#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
(defun policy-deterministic-gate (action context)
- "The main policy gate. Runs invariant checks, then delegates to engineering standards if available.
-Never returns NIL silently; always returns an action or an auditable log event."
+ "The main policy gate entry point.
+
+ This function is registered as the deterministic-fn for the policy skill.
+ It runs invariant checks, then delegates to engineering standards if loaded.
+
+ IMPORTANT: Never returns NIL silently. Always returns either:
+ - An action (possibly modified)
+ - A blocking LOG event with explanation
+ - A warning wrapper with explanation"
+
+ ;; Step 1: Run invariant checks
(let ((current-action (policy-run-invariant-checks action context)))
- ;; If an invariant returned a blocking log, do not proceed further
+
+ ;; Step 2: If an invariant blocked the action, stop here
(when (and (listp current-action)
(member (getf current-action :type) '(:LOG :EVENT))
(eq (getf (getf current-action :payload) :level) :error))
+
(return-from policy-deterministic-gate current-action))
- ;; Delegate to Engineering Standards if loaded
+
+ ;; Step 3: Delegate to Engineering Standards if loaded
(let ((eng-gate (policy-find-engineering-standards-gate)))
(when eng-gate
(setf current-action (funcall eng-gate current-action context))))
+
current-action))
#+end_src
-* Operational Mandates
-Every action performed by an agent in this environment must also adhere to the Engineering Standards. The policy skill evaluates every context (trigger is always true) because invariants are universal.
+* Skill Registration
-** Skill Registration
#+begin_src lisp :tangle ../library/gen/org-skill-policy.lisp
(defskill :skill-policy
:priority 500
@@ -305,6 +555,29 @@ Every action performed by an agent in this environment must also adhere to the E
:deterministic #'policy-deterministic-gate)
#+end_src
+* Quick Reference
+
+** Invariant Quick Reference
+
+| Invariant | Blocks? | Trigger |
+|-----------|---------|---------|
+| Transparency | Yes | Missing `:explanation` on user-facing actions |
+| Autonomy | No | Action references proprietary domain |
+| Bloat | No | Skill file exceeds 50KB |
+| Modularity | Yes | Modification to `harness/` without justification |
+| Mentorship | Yes | High-impact action without `:mentorship-note` |
+| Sustainability | No | Action uses cloud-only provider |
+
+** Required Fields by Action Type
+
+| Action | Required Field | Purpose |
+|--------|---------------|---------|
+| User message | `:explanation` | Transparency |
+| Core modification | `:modularity-justification` | Modularity |
+| Skill creation | `:mentorship-note` | Mentorship |
+| File write | `:mentorship-note` | Mentorship |
+
* See Also
-- [[file:org-skill-engineering-standards.org][Engineering Standards]] (if loaded)
-- [[file:../harness/act.org][Act Stage]] (where the Bouncer and Policy gates are invoked)
+- [[file:org-skill-engineering-standards.org][Engineering Standards]] (if loaded in opencortex-contrib)
+- [[file:../harness/act.org][Act Stage]] - Where Policy and Bouncer gates are invoked
+- [[file:../harness/manifest.org][Manifest]] - The Thin Harness philosophy
\ No newline at end of file