#+PROPERTY: header-args:lisp :tangle (expand-file-name "org-skill-policy.lisp" (expand-file-name "skills/" (or (identity (getenv "INSTALL_DIR")) "."))) :PROPERTIES: :ID: 47425a43-2be0-423c-8509-22592cfe9c9e :CREATED: [2026-04-07 Tue 12:57] :EDITED: [2026-04-22 Wed 16:00] :END: #+TITLE: SKILL: System Policy #+STARTUP: content #+FILETAGS: :platform:policy:alignment:autonomy: * Overview 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, inheriting core harness symbols while maintaining isolation from other skills. #+begin_src lisp (in-package :opencortex) #+end_src * Global Policy Configuration #+begin_src lisp :tangle (expand-file-name "org-skill-policy.lisp" (expand-file-name "skills/" (or (identity (getenv "INSTALL_DIR")) "."))) (defvar *policy-invariant-priorities* '((:transparency . 500) (:autonomy . 400) (:bloat . 300) (:modularity . 250) (:mentorship . 200) (:sustainability . 100)) "Priority alist for policy invariant conflict resolution. 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.") (defvar *proprietary-domain-watchlist* '("googleapis.com" "api.openai.com" "anthropic.com" "api.groq.com" "openrouter.ai") "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.") (defvar *policy-max-skill-size-chars* 50000 "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.") (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 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") (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.") (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.") #+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. | 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 #+end_src * The Core Invariants ** 1. Radical Transparency *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 (defun policy-check-transparency (action context) (defun policy-check-transparency (action context) "Ensures the action is inspectable and user-facing actions carry an explanation. 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)))) ;; Check 2: User-facing actions require explanation (when (and (member target '(:cli :tui :emacs :EMACS :CLI :TUI)) (not explanation) (not (member (getf payload :action) '(:handshake :heartbeat :status-update)))) (return-from policy-check-transparency (list :type :LOG :payload (list :level :error :text "POLICY [Transparency]: User-facing action missing :explanation. Blocked.")))) action)) #+end_src ** 2. Autonomy Above All *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 (defun policy-scan-proprietary-references (action) "Scans ACTION text fields for proprietary domain references. 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)) "")) (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. 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 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))) #+end_src ** 3. Zero-Bloat Mandate *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 (defun policy-check-bloat (action context) "Warns if a :create-skill action exceeds the bloat threshold. 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*) :original-action action)))) action)) #+end_src ** 4. Modularity *The maxim: "The kernel must survive even if all skills fail."* Every system should be decomposed into a minimal, unbreakable core and hot-swappable capabilities. Complexity must live at the edges, never in the kernel. 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 (defun policy-check-modularity (action context) "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))) (justification (or (getf payload :modularity-justification) (getf payload :MODULARITY-JUSTIFICATION)))) (when (and target-file (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)) #+end_src ** 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 (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 (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 (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 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) :payload (list :action :message :text (format nil "[POLICY ~a] ~a" invariant-key message) :explanation (format nil "Invariant: ~a | Rationale: ~a" invariant-key message) :original-action original-action))) #+end_src * The Policy Gate ** Running Invariant Checks #+begin_src lisp (defun policy-run-invariant-checks (action context) "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, interpret it (when (and (listp result) (member (getf result :type) '(:LOG :EVENT))) (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)))))))))) (defun policy-find-engineering-standards-gate () "Searches for the Engineering Standards gate across known jailed package names. 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 (defun policy-deterministic-gate (action context) "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))) ;; 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)) ;; 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 * Skill Registration #+begin_src lisp (defskill :skill-policy :priority 500 :trigger (lambda (ctx) (declare (ignore ctx)) t) :probabilistic nil :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 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