diff --git a/.credo.exs b/.credo.exs new file mode 100644 index 0000000..f3170c1 --- /dev/null +++ b/.credo.exs @@ -0,0 +1,118 @@ +# Credo Configuration +# +# Strict configuration for Valence Shell. +# Run with: mix credo --strict + +%{ + configs: [ + %{ + name: "default", + files: %{ + included: [ + "lib/", + "test/" + ], + excluded: [ + ~r"/_build/", + ~r"/deps/", + ~r"/priv/", + ~r"/proofs/" + ] + }, + plugins: [], + requires: [], + strict: true, + parse_timeout: 5000, + color: true, + checks: %{ + enabled: [ + # Consistency + {Credo.Check.Consistency.ExceptionNames, []}, + {Credo.Check.Consistency.LineEndings, []}, + {Credo.Check.Consistency.ParameterPatternMatching, []}, + {Credo.Check.Consistency.SpaceAroundOperators, []}, + {Credo.Check.Consistency.SpaceInParentheses, []}, + {Credo.Check.Consistency.TabsOrSpaces, []}, + + # Design + {Credo.Check.Design.AliasUsage, [priority: :low, if_nested_deeper_than: 2]}, + {Credo.Check.Design.DuplicatedCode, [priority: :normal]}, + {Credo.Check.Design.TagTODO, [exit_status: 0]}, # Warn but don't fail + {Credo.Check.Design.TagFIXME, []}, + + # Readability + {Credo.Check.Readability.AliasOrder, []}, + {Credo.Check.Readability.FunctionNames, []}, + {Credo.Check.Readability.LargeNumbers, []}, + {Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]}, + {Credo.Check.Readability.ModuleAttributeNames, []}, + {Credo.Check.Readability.ModuleDoc, []}, + {Credo.Check.Readability.ModuleNames, []}, + {Credo.Check.Readability.ParenthesesInCondition, []}, + {Credo.Check.Readability.ParenthesesOnZeroArityDefs, []}, + {Credo.Check.Readability.PipeIntoAnonymousFunctions, []}, + {Credo.Check.Readability.PredicateFunctionNames, []}, + {Credo.Check.Readability.PreferImplicitTry, []}, + {Credo.Check.Readability.RedundantBlankLines, []}, + {Credo.Check.Readability.Semicolons, []}, + {Credo.Check.Readability.SpaceAfterCommas, []}, + {Credo.Check.Readability.StringSigils, []}, + {Credo.Check.Readability.TrailingBlankLine, []}, + {Credo.Check.Readability.TrailingWhiteSpace, []}, + {Credo.Check.Readability.UnnecessaryAliasExpansion, []}, + {Credo.Check.Readability.VariableNames, []}, + {Credo.Check.Readability.WithSingleClause, []}, + + # Refactoring + {Credo.Check.Refactor.Apply, []}, + {Credo.Check.Refactor.CondStatements, []}, + {Credo.Check.Refactor.CyclomaticComplexity, [max_complexity: 10]}, + {Credo.Check.Refactor.FunctionArity, [max_arity: 6]}, + {Credo.Check.Refactor.LongQuoteBlocks, []}, + {Credo.Check.Refactor.MatchInCondition, []}, + {Credo.Check.Refactor.MapJoin, []}, + {Credo.Check.Refactor.NegatedConditionsInUnless, []}, + {Credo.Check.Refactor.NegatedConditionsWithElse, []}, + {Credo.Check.Refactor.Nesting, [max_nesting: 3]}, + {Credo.Check.Refactor.UnlessWithElse, []}, + {Credo.Check.Refactor.WithClauses, []}, + + # Warnings + {Credo.Check.Warning.BoolOperationOnSameValues, []}, + {Credo.Check.Warning.ExpensiveEmptyEnumCheck, []}, + {Credo.Check.Warning.IExPry, []}, + {Credo.Check.Warning.IoInspect, []}, + {Credo.Check.Warning.OperationOnSameValues, []}, + {Credo.Check.Warning.OperationWithConstantResult, []}, + {Credo.Check.Warning.RaiseInsideRescue, []}, + {Credo.Check.Warning.SpecWithStruct, []}, + {Credo.Check.Warning.UnusedEnumOperation, []}, + {Credo.Check.Warning.UnusedFileOperation, []}, + {Credo.Check.Warning.UnusedKeywordOperation, []}, + {Credo.Check.Warning.UnusedListOperation, []}, + {Credo.Check.Warning.UnusedPathOperation, []}, + {Credo.Check.Warning.UnusedRegexOperation, []}, + {Credo.Check.Warning.UnusedStringOperation, []}, + {Credo.Check.Warning.UnusedTupleOperation, []}, + {Credo.Check.Warning.UnsafeExec, []} + ], + disabled: [ + # These are optional extras + {Credo.Check.Readability.StrictModuleLayout, []}, + {Credo.Check.Refactor.ABCSize, []}, + {Credo.Check.Refactor.AppendSingleItem, []}, + {Credo.Check.Refactor.DoubleBooleanNegation, []}, + {Credo.Check.Refactor.ModuleDependencies, []}, + {Credo.Check.Refactor.NegatedIsNil, []}, + {Credo.Check.Refactor.PipeChainStart, []}, + {Credo.Check.Refactor.VariableRebinding, []}, + {Credo.Check.Warning.LazyLogging, []}, + {Credo.Check.Warning.LeakyEnvironment, []}, + {Credo.Check.Warning.MapGetUnsafePass, []}, + {Credo.Check.Warning.MixEnv, []}, + {Credo.Check.Warning.UnsafeToAtom, []} + ] + } + } + ] +} diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 987aab6..4741dd2 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,38 +1,49 @@ --- -name: Bug report -about: Create a report to help us improve -title: "[Bug]: " -labels: 'bug, priority: unset, triage' +name: Bug Report +about: Report a bug in Valence Shell +title: '[BUG] ' +labels: bug assignees: '' - --- -**Describe the bug** -A clear and concise description of what the bug is. +## Bug Description + + + +## To Reproduce + +Steps to reproduce: +1. +2. +3. + +## Expected Behavior + + + +## Actual Behavior + + + +## Environment + +- OS: +- Elixir version: +- Erlang/OTP version: +- Valence Shell version: -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +## Logs/Error Messages -**Expected behavior** -A clear and concise description of what you expected to happen. +\`\`\` + +\`\`\` -**Screenshots** -If applicable, add screenshots to help explain your problem. +## Additional Context -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] + -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] +## Checklist -**Additional context** -Add any other context about the problem here. +- [ ] I have searched existing issues for duplicates +- [ ] I have provided reproduction steps +- [ ] I have included version information diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 3e8fa7e..576d375 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,20 +1,41 @@ --- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: 'enhancement, priority: unset, triage' +name: Feature Request +about: Suggest a new feature for Valence Shell +title: '[FEATURE] ' +labels: enhancement assignees: '' - --- -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] +## Feature Description + + + +## Use Case + + + +## Proposed Solution + + + +## Alternatives Considered + + + +## Reversibility Considerations + + + +- Can this operation be undone? +- What state needs to be captured for compensation? +- Any edge cases for reversibility? + +## Additional Context -**Describe the solution you'd like** -A clear and concise description of what you want to happen. + -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. +## Checklist -**Additional context** -Add any other context or screenshots about the feature request here. +- [ ] I have searched existing issues for duplicates +- [ ] I have considered reversibility implications +- [ ] This aligns with the project's goals (reversible, POSIX-compatible shell) diff --git a/.github/ISSUE_TEMPLATE/proof_request.md b/.github/ISSUE_TEMPLATE/proof_request.md new file mode 100644 index 0000000..635359f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/proof_request.md @@ -0,0 +1,52 @@ +--- +name: Proof Request +about: Request a new formal proof or verification +title: '[PROOF] ' +labels: formal-verification +assignees: '' +--- + +## Theorem Description + + + +## Formal Statement + + + +```coq +(* Example: *) +Theorem new_property : + forall x, P(x) -> Q(x). +``` + +## Motivation + + + +## Scope + +- [ ] Core reversibility property +- [ ] Composition theorem +- [ ] Independence/non-interference +- [ ] Error handling correctness +- [ ] Other: + +## Target Proof Systems + + + +- [ ] Coq (required) +- [ ] Lean 4 +- [ ] Agda +- [ ] Isabelle/HOL +- [ ] Mizar +- [ ] Z3 (SMT) + +## Prerequisites + + + +## Additional Context + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..ca2d37b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,51 @@ +## Summary + + + +## Type of Change + +- [ ] Bug fix (non-breaking change fixing an issue) +- [ ] New feature (non-breaking change adding functionality) +- [ ] Breaking change (fix or feature causing existing functionality to change) +- [ ] Documentation update +- [ ] Proof addition/modification +- [ ] Refactoring (no functional changes) + +## Checklist + +### Code Quality +- [ ] Code follows the project style guidelines (`mix format`) +- [ ] Credo passes without errors (`mix credo --strict`) +- [ ] Tests pass (`mix test`) +- [ ] New code has appropriate tests + +### Reversibility (for command implementations) +- [ ] Implements `Valence.Command` behaviour +- [ ] `execute/2` returns proper compensation +- [ ] `compensate/2` correctly reverses the operation +- [ ] `verify/1` detects drift + +### Formal Verification (if modifying proofs) +- [ ] Coq proofs compile (`just prove`) +- [ ] No new `Admitted` or `sorry` +- [ ] Cross-validation in at least 2 proof systems + +### Documentation +- [ ] README updated (if needed) +- [ ] CHANGELOG updated +- [ ] Docstrings added for new public functions + +### Sacred Files +- [ ] I have NOT modified sacred files (README.adoc, STATE.adoc, ARCHITECTURE.md, META.scm) without explicit approval + +## Related Issues + + + +## Testing + + + +## Screenshots (if applicable) + + diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index f56c346..8a6f1c2 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -1,39 +1,100 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. +# Valence Shell - Elixir CI +# +# Runs on push to main and all PRs. +# Tests, linting, formatting, and type checking. name: Elixir CI on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] permissions: contents: read jobs: build: - name: Build and test runs-on: ubuntu-latest + env: + MIX_ENV: test + + steps: + - uses: actions/checkout@v4 + + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: "1.15" + otp-version: "26" + + - name: Restore dependencies cache + uses: actions/cache@v4 + with: + path: | + deps + _build + key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }} + restore-keys: | + ${{ runner.os }}-mix- + + - name: Install dependencies + run: mix deps.get + + - name: Check formatting + run: mix format --check-formatted + + - name: Compile (warnings as errors) + run: mix compile --warnings-as-errors + + - name: Run Credo + run: mix credo --strict + + - name: Run tests + run: mix test + + dialyzer: + name: Dialyzer + runs-on: ubuntu-latest + + env: + MIX_ENV: dev + steps: - - uses: actions/checkout@v6.0.1 - - name: Set up Elixir - uses: erlef/setup-beam@e6d7c94229049569db56a7ad5a540c051a010af9 # v1.20.4 - with: - elixir-version: '1.15.2' # [Required] Define the Elixir version - otp-version: '26.0' # [Required] Define the Erlang/OTP version - - name: Restore dependencies cache - uses: actions/cache@v5 - with: - path: deps - key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }} - restore-keys: ${{ runner.os }}-mix- - - name: Install dependencies - run: mix deps.get - - name: Run tests - run: mix test + - uses: actions/checkout@v4 + + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: "1.15" + otp-version: "26" + + - name: Restore dependencies cache + uses: actions/cache@v4 + with: + path: | + deps + _build + key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }} + restore-keys: | + ${{ runner.os }}-mix- + + - name: Restore PLT cache + uses: actions/cache@v4 + with: + path: priv/plts + key: ${{ runner.os }}-plt-${{ hashFiles('**/mix.lock') }} + restore-keys: | + ${{ runner.os }}-plt- + + - name: Install dependencies + run: mix deps.get + + - name: Create PLTs directory + run: mkdir -p priv/plts + + - name: Run Dialyzer + run: mix dialyzer diff --git a/AGENTIC.scm b/AGENTIC.scm new file mode 100644 index 0000000..1809c17 --- /dev/null +++ b/AGENTIC.scm @@ -0,0 +1,332 @@ +;; AGENTIC.scm — Agentic AI Augmentation Policy +;; SPDX-License-Identifier: AGPL-3.0-or-later +;; SPDX-FileCopyrightText: 2025 Jonathan D.A. Jewell +;; +;; Defines how AI agents interact with Valence Shell: +;; - Capabilities and constraints +;; - Delegation boundaries +;; - Verification requirements +;; - Human-in-the-loop policies + +(agentic + (version . "0.1.0") + (project . "valence-shell") + (purpose . "AI agent integration policy for reversible shell operations")) + +;;; =================================================================== +;;; AGENT CAPABILITY MODEL +;;; =================================================================== + +(capability-model + + ;; Capability tiers - what agents can do autonomously + (tiers + ((tier . 0) + (name . "read-only") + (description . "Observe state, no mutations") + (allowed . ("ls" "cat" "pwd" "history" "verify")) + (requires-approval . #f)) + + ((tier . 1) + (name . "safe-reversible") + (description . "Operations with proven reversibility") + (allowed . ("mkdir" "rmdir" "touch" "cp" "mv")) + (requires-approval . #f) + (constraint . "Only within sandbox path")) + + ((tier . 2) + (name . "warn-reversible") + (description . "Reversible but with side effects") + (allowed . ("write" "chmod" "chown")) + (requires-approval . "batch > 5 operations") + (constraint . "Log all operations")) + + ((tier . 3) + (name . "dangerous") + (description . "Potentially irreversible") + (allowed . ("rm" "rm -rf" "external API calls")) + (requires-approval . #t) + (constraint . "Explicit human confirmation per operation")) + + ((tier . 4) + (name . "forbidden") + (description . "Never allowed for agents") + (forbidden . ("sudo" "su" "chroot" "mount" "format" "dd")) + (constraint . "Hard block, no override"))) + + ;; Default tier for unknown operations + (default-tier . 3)) + +;;; =================================================================== +;;; DELEGATION POLICY +;;; =================================================================== + +(delegation-policy + + ;; When can an agent act autonomously? + (autonomous-conditions + ((condition . "Operation tier <= agent's authorized tier") + (check . "agent.tier >= operation.tier")) + + ((condition . "Operation within sandbox boundaries") + (check . "path.starts_with?(agent.sandbox_root)")) + + ((condition . "Rate limit not exceeded") + (check . "agent.ops_this_minute < agent.rate_limit")) + + ((condition . "No pending human review") + (check . "agent.pending_approvals.empty?()"))) + + ;; Escalation triggers + (escalation-triggers + ("Operation requires higher tier than authorized") + ("Path outside sandbox") + ("Rate limit exceeded") + ("Compensation failed") + ("Drift detected during verification") + ("Batch size exceeds threshold") + ("External system interaction")) + + ;; Escalation protocol + (escalation-protocol + ((step . 1) + (action . "Pause agent execution")) + ((step . 2) + (action . "Generate human-readable summary of intended action")) + ((step . 3) + (action . "Present options: approve / reject / modify / delegate")) + ((step . 4) + (action . "On approve: execute with audit trail") + (action . "On reject: log and return error to agent") + (action . "On modify: agent re-plans with constraints") + (action . "On delegate: escalate to higher authority")))) + +;;; =================================================================== +;;; VERIFICATION REQUIREMENTS +;;; =================================================================== + +(verification-requirements + + ;; Pre-execution verification + (pre-execution + ((name . "precondition-check") + (description . "Verify preconditions before execution") + (applies-to . "all operations") + (action . "Call command.verify/1 on current state")) + + ((name . "dry-run") + (description . "Simulate operation without mutation") + (applies-to . "tier >= 2") + (action . "Execute with :dry_run flag, return diff")) + + ((name . "impact-assessment") + (description . "Estimate scope of changes") + (applies-to . "batch operations") + (output . "List of affected paths, estimated reversibility"))) + + ;; Post-execution verification + (post-execution + ((name . "state-verification") + (description . "Confirm operation achieved intended result") + (action . "Call command.verify/1, compare expected vs actual")) + + ((name . "compensation-readiness") + (description . "Verify compensation is executable") + (action . "Validate compensation args, check preconditions")) + + ((name . "audit-log") + (description . "Record operation for accountability") + (fields . ("agent_id" "operation" "args" "result" + "compensation" "timestamp" "session_id"))))) + +;;; =================================================================== +;;; AGENT IDENTITY AND TRUST +;;; =================================================================== + +(agent-identity + + ;; Agent registration + (registration + ((field . "agent_id") + (type . "UUID") + (generated . "On first connection")) + + ((field . "agent_class") + (type . "enum") + (values . ("claude" "copilot" "custom" "human-proxied"))) + + ((field . "authorized_tier") + (type . "integer 0-3") + (default . 1)) + + ((field . "sandbox_root") + (type . "path") + (required . #t)) + + ((field . "rate_limit") + (type . "ops/minute") + (default . 60))) + + ;; Trust levels + (trust-levels + ((level . "untrusted") + (tier . 0) + (description . "New agent, read-only until verified")) + + ((level . "basic") + (tier . 1) + (description . "Verified agent, safe reversible ops")) + + ((level . "elevated") + (tier . 2) + (description . "Trusted agent, warn-level ops")) + + ((level . "privileged") + (tier . 3) + (description . "Highly trusted, can request dangerous ops")) + + ((level . "human-equivalent") + (tier . 4) + (description . "Human-in-the-loop, full access with confirmation")))) + +;;; =================================================================== +;;; HUMAN-IN-THE-LOOP POLICIES +;;; =================================================================== + +(human-in-the-loop + + ;; When human must be involved + (mandatory-human + ("First operation in new sandbox") + ("Any tier-3 (dangerous) operation") + ("Compensation failure") + ("Rate limit exceeded 3x") + ("Agent requests tier elevation") + ("External system interaction") + ("Session running > 4 hours without check-in")) + + ;; Human override capabilities + (human-overrides + ((name . "force-execute") + (description . "Execute operation bypassing agent tier") + (audit . "Full operation logged with human ID")) + + ((name . "force-compensate") + (description . "Manually trigger compensation") + (audit . "Compensation logged with reason")) + + ((name . "revoke-agent") + (description . "Immediately terminate agent session") + (action . "Compensate all pending, clear state")) + + ((name . "elevate-tier") + (description . "Temporarily increase agent capabilities") + (duration . "Single operation or time-limited"))) + + ;; Notification channels + (notifications + ((channel . "terminal") + (for . "Interactive sessions") + (format . "Inline prompt")) + + ((channel . "webhook") + (for . "Headless/daemon mode") + (format . "JSON payload")) + + ((channel . "queue") + (for . "Async approval workflows") + (format . "Persistent message")))) + +;;; =================================================================== +;;; CONATIVE GATING INTEGRATION +;;; =================================================================== + +(conative-gating + + ;; Integration with github.com/hyperpolymath/conative-gating + (integration + (enabled . #t) + (purpose . "AI enforcement layer for agent behavior")) + + ;; Gating rules + (rules + ((rule . "no-sacred-file-modification") + (condition . "path in SACRED_FILES") + (action . "block") + (message . "Sacred files require human modification")) + + ((rule . "no-language-contamination") + (condition . "file.extension in BANNED_EXTENSIONS") + (action . "block") + (message . "Banned language file creation blocked")) + + ((rule . "sandbox-enforcement") + (condition . "NOT path.starts_with?(agent.sandbox)") + (action . "block") + (message . "Operation outside agent sandbox")) + + ((rule . "rate-limit-enforcement") + (condition . "agent.ops_this_minute >= agent.rate_limit") + (action . "pause") + (message . "Rate limit reached, pausing agent"))) + + ;; Banned extensions (RSR policy) + (banned-extensions . (".py" ".ts" ".coffee" ".go"))) + +;;; =================================================================== +;;; AGENT SESSION LIFECYCLE +;;; =================================================================== + +(session-lifecycle + + ;; Session initialization + (on-connect + ("Authenticate agent") + ("Assign sandbox root") + ("Set initial tier based on trust level") + ("Initialize rate limiter") + ("Create session journal")) + + ;; Session maintenance + (heartbeat + (interval . "60 seconds") + (on-miss . "Pause agent, require re-authentication")) + + ;; Session termination + (on-disconnect + ((graceful . #t) + (actions . ("Complete pending operations" + "Verify all compensations stored" + "Archive session journal" + "Release sandbox lock"))) + + ((graceful . #f) + (actions . ("Mark session as crashed" + "Flag pending operations for recovery" + "Notify human of unclean shutdown"))))) + +;;; =================================================================== +;;; METRICS AND OBSERVABILITY +;;; =================================================================== + +(observability + + ;; Metrics to track + (metrics + ("agent.operations.total" . "counter") + ("agent.operations.by_tier" . "counter") + ("agent.escalations" . "counter") + ("agent.compensations" . "counter") + ("agent.drift_detected" . "counter") + ("agent.session_duration" . "histogram")) + + ;; Audit events + (audit-events + ("agent.connected") + ("agent.operation.requested") + ("agent.operation.approved") + ("agent.operation.rejected") + ("agent.operation.executed") + ("agent.escalation.triggered") + ("agent.human.override") + ("agent.disconnected"))) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..f009cc2 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,248 @@ +# Architecture + +**Status:** This is a SACRED FILE. Do not modify without explicit human approval. + +## Overview + +Valence Shell is a reversible shell implementing the Saga pattern. Every command is a transaction with an inverse function. + +``` +F⁻¹(F(s)) = s — Full reversibility without losing POSIX compliance +``` + +## Core Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ User / Agent │ +└─────────────────────────┬───────────────────────────────────┘ + │ Command + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Valence.Saga │ +│ Orchestrates multi-step transactions with compensation │ +└─────────────────────────┬───────────────────────────────────┘ + │ + ┌───────────────┼───────────────┐ + │ │ │ + ▼ ▼ ▼ +┌─────────────┐ ┌─────────────┐ ┌─────────────┐ +│ Journal │ │ History │ │ Command │ +│ Idempotency │ │ Zipper │ │ Behaviour │ +│ + Recovery │ │ Undo/Redo │ │ 4 Callbacks│ +└─────────────┘ └─────────────┘ └─────────────┘ +``` + +## The Three Phases + +### Phase 1: Hypervisor (Current) + +``` +┌─────────────────────────────────────────┐ +│ Valence Shell │ +│ ┌─────────────────────────────────┐ │ +│ │ Native Reversible Commands │ │ +│ │ (mkdir, touch, cp, mv, etc.) │ │ +│ └─────────────────────────────────┘ │ +│ │ │ +│ │ Fallthrough │ +│ ▼ │ +│ ┌─────────────────────────────────┐ │ +│ │ /bin/sh │ │ +│ │ (Unrecognized commands) │ │ +│ └─────────────────────────────────┘ │ +└─────────────────────────────────────────┘ +``` + +- Native commands execute with full transaction semantics +- Unknown commands pass through to underlying shell +- All output captured for history + +### Phase 2: Hybrid Shim (Future) + +``` +┌─────────────────────────────────────────┐ +│ Valence Shell │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────┐ │ +│ │ LD_PRELOAD / ptrace / eBPF │ │ +│ │ Syscall Interception Layer │ │ +│ └─────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────┐ │ +│ │ Copy-on-Write Enforcement │ │ +│ └─────────────────────────────────┘ │ +└─────────────────────────────────────────┘ +``` + +- Intercept filesystem syscalls from any binary +- Transparent to the command being run +- Extends reversibility to ALL commands + +### Phase 3: AST Transpiler (Dream) + +``` +┌─────────────────────────────────────────┐ +│ Shell Script │ +│ for f in *.txt; do mv $f $f.bak; done │ +└─────────────────────────┬───────────────┘ + │ Parse + ▼ +┌─────────────────────────────────────────┐ +│ Elixir AST │ +│ Enum.each(glob("*.txt"), &move/1) │ +└─────────────────────────┬───────────────┘ + │ Analyze + ▼ +┌─────────────────────────────────────────┐ +│ Side Effect Analysis │ +│ - Files affected: *.txt │ +│ - Operation: rename │ +│ - Compensation: reverse rename │ +└─────────────────────────────────────────┘ +``` + +## Component Details + +### Valence.Command Behaviour + +Every reversible operation implements four callbacks: + +```elixir +@callback describe(args) :: :safe | :warn | :danger +@callback execute(args, key) :: {:ok, result, compensation} | {:error, reason} +@callback compensate(args, key) :: :ok | {:error, reason} +@callback verify(args) :: :ok | {:drift, expected, actual} +``` + +### Valence.History.Zipper + +O(1) undo/redo using a functional zipper structure: + +``` + Past (reversed) │ Future + [cmd3, cmd2, cmd1] │ [cmd4, cmd5] + │ + ◄── back() cursor forward() ──► +``` + +- `push/1` — Add to history, clear redo stack +- `back/1` — Move cursor backward (undo) +- `forward/1` — Move cursor forward (redo) + +### Valence.Journal + +Idempotency and crash recovery: + +``` +Key: UUID ─────► Entry: {state, command, args, compensation} + │ + ├── :pending (started) + ├── :completed (success) + ├── :compensated (rolled back) + └── :failed (error) +``` + +On restart, pending entries are recovered via `verify/1`. + +### Valence.Saga + +Compensating transaction orchestration: + +``` +Step 1 ──► Step 2 ──► Step 3 ──► FAIL! + │ + ▼ +Comp 1 ◄── Comp 2 ◄── Comp 3 ◄────┘ +``` + +All-or-nothing semantics: either every step succeeds, or all are rolled back. + +## Technology Choices + +| Component | Choice | Rationale | +|-----------|--------|-----------| +| Runtime | Elixir/OTP | Supervision trees, pattern matching, no Python | +| Transactions | Ecto | Changeset semantics without database coupling | +| History | Zipper | O(1) navigation, functional, immutable | +| Proofs | Coq | Machine-checked, ECHIDNA integration | +| Containers | Podman | OCI-compliant, rootless, no Docker daemon | + +## Security Model + +### Trust Boundaries + +``` +┌─────────────────────────────────────┐ +│ Formal Proofs (HIGH TRUST) │ Mathematical guarantees +│ Coq/Lean/Agda/Isabelle/Mizar │ +└─────────────┬───────────────────────┘ + │ Extraction (GAP) +┌─────────────▼───────────────────────┐ +│ Elixir Implementation (MEDIUM) │ Type safe, pattern matching +└─────────────┬───────────────────────┘ + │ FFI (GAP) +┌─────────────▼───────────────────────┐ +│ POSIX Syscalls (LOW TRUST) │ Kernel guarantees only +└──────────────────────────────────────┘ +``` + +### Agent Capabilities + +Tier 0: Read-only (ls, cat, pwd) +Tier 1: Safe reversible (mkdir, touch) +Tier 2: Warn reversible (write, chmod) +Tier 3: Dangerous (rm, external APIs) +Tier 4: Forbidden (sudo, mount) + +## Integration Points + +- **ECHIDNA** — Multi-solver proof verification +- **Svalinn** — Container base images +- **Cerro Torre** — Orchestration patterns +- **Conative Gating** — AI enforcement layer + +## Decision Log + +### ADR-001: Elixir over Rust + +**Context:** Need a runtime for the shell core. + +**Decision:** Use Elixir/OTP. + +**Rationale:** +- OTP supervision trees handle crashes gracefully +- Pattern matching ideal for command parsing +- Ecto provides transaction semantics +- No Python contamination risk + +### ADR-002: Zipper over Stack + +**Context:** Need undo/redo data structure. + +**Decision:** Use Zipper instead of two stacks. + +**Rationale:** +- Single coherent data structure +- O(1) for all navigation operations +- Well-understood from Haskell/Clojure +- Immutable, easy to reason about + +### ADR-003: Coq for Proofs + +**Context:** Need formal verification of reversibility. + +**Decision:** Use Coq as primary, cross-validate with ECHIDNA. + +**Rationale:** +- Mature ecosystem +- Extraction to OCaml +- ECHIDNA supports multi-solver validation +- Academic credibility for MAA Framework + +--- + +**Last Updated:** 2025-12-18 +**Version:** 0.1.0-alpha diff --git a/NEUROSYM.scm b/NEUROSYM.scm new file mode 100644 index 0000000..0f63f75 --- /dev/null +++ b/NEUROSYM.scm @@ -0,0 +1,371 @@ +;; NEUROSYM.scm — Neurosymbolic Integration Policy +;; SPDX-License-Identifier: AGPL-3.0-or-later +;; SPDX-FileCopyrightText: 2025 Jonathan D.A. Jewell +;; +;; Defines the integration between neural (LLM) and symbolic (formal proofs) +;; components in Valence Shell. NeSy = Neurosymbolic AI. +;; +;; Core principle: Neural systems propose, symbolic systems verify. + +(neurosym + (version . "0.1.0") + (project . "valence-shell") + (purpose . "Neural-symbolic integration for verified shell operations")) + +;;; =================================================================== +;;; ARCHITECTURE OVERVIEW +;;; =================================================================== + +(architecture + + ;; The hybrid stack + (layers + ((layer . "neural") + (role . "intention parsing, plan generation, natural language") + (components . ("LLM" "embeddings" "retrieval")) + (trust . "low - must be verified")) + + ((layer . "symbolic") + (role . "formal verification, proof checking, invariant enforcement") + (components . ("Coq" "ECHIDNA" "type system")) + (trust . "high - mathematical guarantees")) + + ((layer . "bridge") + (role . "translation between neural and symbolic representations") + (components . ("DSL parser" "proof sketch generator" "counterexample analyzer")) + (trust . "medium - correctness depends on implementation"))) + + ;; Data flow + (flow + "User intent (natural language)" + " → Neural: Parse to structured command" + " → Bridge: Translate to formal specification" + " → Symbolic: Check preconditions, generate proof obligations" + " → Bridge: Translate proof result to execution decision" + " → Execution: Run verified command" + " → Symbolic: Verify postconditions" + " → Neural: Generate human-readable summary")) + +;;; =================================================================== +;;; NEURAL COMPONENT POLICY +;;; =================================================================== + +(neural-policy + + ;; What neural components can do + (capabilities + ((capability . "intent-parsing") + (description . "Convert natural language to structured command") + (example . "'make a backup of config' → Valence.Commands.Copy{src: 'config', dst: 'config.bak'}")) + + ((capability . "plan-generation") + (description . "Propose multi-step operation sequences") + (constraint . "Plans must be validated symbolically before execution")) + + ((capability . "error-explanation") + (description . "Translate symbolic errors to natural language") + (example . "{:drift, :exists, :missing} → 'Expected file to exist but it was not found'")) + + ((capability . "compensation-suggestion") + (description . "Propose recovery actions when compensation fails") + (constraint . "Suggestions must be verified before execution"))) + + ;; What neural components CANNOT do + (limitations + ("Cannot execute commands directly - must go through symbolic layer") + ("Cannot bypass formal verification") + ("Cannot modify proof obligations") + ("Cannot override safety constraints") + ("Cannot access files outside sandbox")) + + ;; Model requirements + (model-requirements + ((requirement . "structured-output") + (description . "Must produce parseable command structures") + (format . "JSON or S-expression")) + + ((requirement . "uncertainty-aware") + (description . "Must express confidence levels") + (threshold . "Operations only proceed if confidence > 0.8")) + + ((requirement . "explainable") + (description . "Must provide reasoning chain") + (use . "Audit trail and human review")))) + +;;; =================================================================== +;;; SYMBOLIC COMPONENT POLICY +;;; =================================================================== + +(symbolic-policy + + ;; Proof systems in use + (proof-systems + ((system . "coq") + (role . "Primary verification - reversibility proofs") + (location . "proofs/coq/") + (trust . "highest")) + + ((system . "echidna") + (role . "Multi-solver verification") + (integration . "github.com/hyperpolymath/echidna") + (solvers . ("coq" "lean4" "agda" "isabelle" "mizar" "z3"))) + + ((system . "elixir-types") + (role . "Runtime type checking via dialyzer") + (trust . "medium"))) + + ;; Verification requirements + (verification-requirements + ((operation-class . "reversible") + (proof-required . "F⁻¹(F(s)) = s for operation F") + (verified-in . ("coq" "lean4"))) + + ((operation-class . "composition") + (proof-required . "Sequence reversibility") + (verified-in . ("coq" "agda"))) + + ((operation-class . "independence") + (proof-required . "Operations on different paths don't interfere") + (verified-in . ("coq" "isabelle")))) + + ;; Proof obligation generation + (proof-obligations + ((trigger . "New command implementation") + (obligations + ("Reversibility theorem") + ("Precondition characterization") + ("Compensation correctness"))) + + ((trigger . "Command composition") + (obligations + ("Sequence reversibility") + ("Independence from other operations"))))) + +;;; =================================================================== +;;; BRIDGE LAYER +;;; =================================================================== + +(bridge-layer + + ;; Neural → Symbolic translation + (neural-to-symbolic + ((input . "Structured command from LLM") + (output . "Formal specification in proof language") + (process + ((step . 1) + (action . "Parse command structure")) + ((step . 2) + (action . "Look up formal model for command type")) + ((step . 3) + (action . "Instantiate with concrete arguments")) + ((step . 4) + (action . "Generate proof obligations")))) + + ;; Example translation + (example + (neural-output . "{command: 'mkdir', args: {path: '/tmp/foo'}}") + (symbolic-spec . "(mkdir '/tmp/foo' fs)") + (proof-obligation . "rmdir '/tmp/foo' (mkdir '/tmp/foo' fs) = fs"))) + + ;; Symbolic → Neural translation + (symbolic-to-neural + ((input . "Proof result or error") + (output . "Natural language explanation") + (templates + ((pattern . "proof-success") + (template . "Operation verified: {operation} is reversible")) + + ((pattern . "proof-failure") + (template . "Verification failed: {reason}. The operation {operation} may not be reversible because {explanation}")) + + ((pattern . "precondition-violation") + (template . "Cannot proceed: {precondition} is not satisfied")) + + ((pattern . "drift-detected") + (template . "State mismatch: expected {expected}, found {actual}"))))) + + ;; Counterexample analysis + (counterexample-handling + ((on-counterexample + (action . "Translate to concrete scenario") + (present . "Show user what would go wrong") + (suggest . "Alternative approaches that satisfy constraints"))))) + +;;; =================================================================== +;;; VERIFICATION PIPELINE +;;; =================================================================== + +(verification-pipeline + + ;; Fast path: already verified + (fast-path + (condition . "Command has cached proof certificate") + (action . "Check certificate validity, execute")) + + ;; Standard path: verification required + (standard-path + ((phase . "pre-check") + (actions + ("Parse command") + ("Load formal model") + ("Check preconditions symbolically"))) + + ((phase . "proof-check") + (actions + ("Retrieve or generate proof obligation") + ("Verify with primary prover (Coq)") + ("Optional: cross-validate with ECHIDNA"))) + + ((phase . "execute") + (condition . "Proof check passed") + (actions + ("Execute command") + ("Record compensation") + ("Verify postcondition"))) + + ((phase . "reject") + (condition . "Proof check failed") + (actions + ("Log failure reason") + ("Translate to natural language") + ("Suggest alternatives if possible")))) + + ;; Slow path: novel operation + (slow-path + (condition . "No existing proof for operation pattern") + (actions + ("Flag for human review") + ("Optionally: attempt proof synthesis") + ("Cache result for future use")))) + +;;; =================================================================== +;;; ECHIDNA INTEGRATION +;;; =================================================================== + +(echidna-integration + + ;; ECHIDNA: Multi-solver proof verification + (purpose . "Cross-validate proofs across multiple proof systems") + + (configuration + ((solvers . ("coq" "lean4" "agda" "isabelle" "mizar" "z3")) + (mode . "consensus") + (threshold . "majority (4/6)") + (timeout . "60 seconds per solver"))) + + ;; Verification workflow + (workflow + ((step . 1) + (action . "Submit proof obligation to ECHIDNA")) + ((step . 2) + (action . "ECHIDNA distributes to configured solvers")) + ((step . 3) + (action . "Collect results with proofs/counterexamples")) + ((step . 4) + (action . "Aggregate: consensus, majority, or conflict")) + ((step . 5) + (action . "Return verdict with confidence level"))) + + ;; Conflict resolution + (conflict-resolution + ((scenario . "Solvers disagree") + (action . "Flag for human review") + (data . "Provide all proofs and counterexamples")) + + ((scenario . "Timeout on some solvers") + (action . "Proceed with available results if threshold met") + (warning . "Mark as partially verified")))) + +;;; =================================================================== +;;; LEARNING AND ADAPTATION +;;; =================================================================== + +(learning + + ;; Proof caching + (proof-cache + (storage . "Local + distributed") + (key . "(command-type, argument-patterns)") + (value . "(proof-certificate, validation-timestamp)") + (ttl . "Until proof system update")) + + ;; Pattern learning + (pattern-learning + (purpose . "Learn common operation sequences for faster verification") + (input . "Successful operation sequences") + (output . "Reusable composition proofs") + (constraint . "Human approval for new patterns")) + + ;; Failure learning + (failure-learning + (purpose . "Learn from verification failures to improve suggestions") + (input . "Failed proof attempts with counterexamples") + (output . "Updated heuristics for neural planner") + (constraint . "Does not affect symbolic verification"))) + +;;; =================================================================== +;;; TRUST AND AUDIT +;;; =================================================================== + +(trust-model + + ;; Trust hierarchy + (hierarchy + ((level . 1) + (component . "Formal proofs (Coq, etc.)") + (trust . "Mathematical certainty")) + + ((level . 2) + (component . "ECHIDNA cross-validation") + (trust . "High - multiple independent verifications")) + + ((level . 3) + (component . "Type system (Elixir/Dialyzer)") + (trust . "Medium - compile-time guarantees")) + + ((level . 4) + (component . "Neural components") + (trust . "Low - must be verified symbolically"))) + + ;; Audit trail + (audit + (events + ("Neural interpretation generated") + ("Proof obligation created") + ("Verification attempted") + ("Verification succeeded/failed") + ("Execution approved/rejected") + ("Compensation recorded")) + + (retention . "Indefinite for security-relevant operations") + (format . "Structured log with cryptographic integrity"))) + +;;; =================================================================== +;;; RESEARCH DIRECTIONS +;;; =================================================================== + +(research-directions + + ;; Future capabilities + (planned + ((name . "proof-synthesis") + (description . "Neural-guided proof search") + (status . "research") + (constraint . "All synthesized proofs must be machine-checked")) + + ((name . "natural-language-proofs") + (description . "Explain proofs in natural language") + (status . "research") + (use . "Education and debugging")) + + ((name . "adversarial-robustness") + (description . "Detect attempts to bypass verification") + (status . "planned") + (importance . "critical for production"))) + + ;; Open questions + (open-questions + ("How to handle probabilistic neural outputs in deterministic verification?") + ("Can we verify neural component behavior formally?") + ("What is the right balance between verification thoroughness and latency?") + ("How to handle partial verification when full proof is intractable?"))) diff --git a/PLAYBOOK.scm b/PLAYBOOK.scm new file mode 100644 index 0000000..04e31a2 --- /dev/null +++ b/PLAYBOOK.scm @@ -0,0 +1,205 @@ +;; PLAYBOOK.scm — Valence Shell Operational Playbooks +;; SPDX-License-Identifier: AGPL-3.0-or-later +;; SPDX-FileCopyrightText: 2025 Jonathan D.A. Jewell +;; +;; Defines operational patterns, recovery procedures, and standard workflows. +;; Machine-readable runbooks for both humans and AI agents. + +(playbook + (version . "0.1.0") + (project . "valence-shell") + (purpose . "Operational patterns for reversible shell operations")) + +;;; =================================================================== +;;; RECOVERY PLAYBOOKS +;;; =================================================================== + +(recovery-playbooks + + ;; Crash recovery: pending transactions + ((name . "recover-pending-transactions") + (trigger . "Application restart with pending journal entries") + (steps + ((step . 1) + (action . "Query journal for :pending entries") + (command . "Valence.Journal.pending_entries()")) + ((step . 2) + (action . "For each pending entry, verify state") + (command . "entry.command.verify(entry.args)")) + ((step . 3) + (action . "If :ok, mark completed; if :drift, compensate") + (decision + (on-ok . "Journal.complete(key, :recovered, nil)") + (on-drift . "Journal.fail(key, :incomplete)")))) + (postcondition . "No pending entries remain")) + + ;; Undo cascade failure + ((name . "undo-cascade-recovery") + (trigger . "Compensation fails during undo") + (steps + ((step . 1) + (action . "Log failure with full context") + (data . "(command, args, compensation, error)")) + ((step . 2) + (action . "Attempt idempotent retry (max 3)") + (retry-policy . ((max-attempts . 3) (backoff . exponential)))) + ((step . 3) + (action . "If still failing, escalate to human") + (escalation . "Create recovery ticket with state snapshot"))) + (postcondition . "Either compensated or human notified")) + + ;; Two Generals drift detection + ((name . "drift-reconciliation") + (trigger . "verify/1 returns {:drift, expected, actual}") + (steps + ((step . 1) + (action . "Log drift event with full state")) + ((step . 2) + (action . "Determine if reconcilable") + (decision + (reconcilable . "Apply corrective operation") + (not-reconcilable . "Escalate with snapshot"))) + ((step . 3) + (action . "Update journal with reconciliation result"))) + (postcondition . "State matches expected or human notified"))) + +;;; =================================================================== +;;; OPERATIONAL PATTERNS +;;; =================================================================== + +(operational-patterns + + ;; Standard command execution flow + ((name . "execute-command") + (pattern . "saga") + (flow + ((phase . "pre-flight") + (actions . ("Generate idempotency key" + "Check journal for prior execution" + "Assess risk level via describe/1"))) + ((phase . "execution") + (actions . ("Call execute/2" + "Capture compensation" + "Record in journal as :pending"))) + ((phase . "commit") + (actions . ("Mark journal :completed" + "Push to history zipper" + "Return result"))) + ((phase . "rollback") + (trigger . "execution failure") + (actions . ("Mark journal :failed" + "No compensation needed (nothing changed)"))))) + + ;; Batch operation pattern + ((name . "batch-execute") + (pattern . "saga-sequence") + (description . "Execute multiple commands as atomic unit") + (flow + ((phase . "collect") + (action . "Gather all commands with args")) + ((phase . "validate") + (action . "Pre-check all preconditions")) + ((phase . "execute") + (action . "Execute in order, collecting compensations")) + ((phase . "commit-or-rollback") + (on-success . "Commit all to history as single entry") + (on-failure . "Compensate in reverse order")))) + + ;; Interactive session pattern + ((name . "interactive-session") + (pattern . "repl-with-history") + (features + ("Undo last command: Ctrl+Z or 'undo'") + ("Redo undone command: Ctrl+Y or 'redo'") + ("Show history: 'history'") + ("Jump to point: 'history goto N'")))) + +;;; =================================================================== +;;; DANGER ZONE PLAYBOOKS +;;; =================================================================== + +(danger-playbooks + + ;; Handling :danger operations + ((name . "danger-confirmation") + (trigger . "describe/1 returns :danger") + (steps + ((step . 1) + (action . "Display warning with impact assessment")) + ((step . 2) + (action . "Require explicit confirmation") + (prompt . "This operation may be irreversible. Proceed? [y/N]")) + ((step . 3) + (action . "If confirmed, capture maximum state for compensation") + (capture . "Full file content, permissions, ownership, timestamps"))) + (note . "Danger ops get extra state capture for best-effort recovery")) + + ;; External system compensation + ((name . "external-compensation") + (trigger . "Operation affects external system (API, DB, network)") + (steps + ((step . 1) + (action . "Generate compensating transaction BEFORE execution") + (example . "DELETE /api/resource/123 → POST /api/resource with saved body")) + ((step . 2) + (action . "Store compensation with TTL") + (ttl . "24 hours default, configurable")) + ((step . 3) + (action . "On undo, execute compensation") + (warning . "External state may have changed - verify first"))) + (limitation . "Cannot guarantee external system reversibility"))) + +;;; =================================================================== +;;; MAINTENANCE PLAYBOOKS +;;; =================================================================== + +(maintenance-playbooks + + ;; Journal compaction + ((name . "compact-journal") + (trigger . "Journal size exceeds threshold OR weekly schedule") + (steps + ((step . 1) + (action . "Archive completed entries older than retention period")) + ((step . 2) + (action . "Verify no pending entries in archive range")) + ((step . 3) + (action . "Write archive to persistent storage")) + ((step . 4) + (action . "Truncate active journal"))) + (retention . "7 days default, configurable")) + + ;; History pruning + ((name . "prune-history") + (trigger . "History depth exceeds limit") + (steps + ((step . 1) + (action . "Identify oldest entries beyond limit")) + ((step . 2) + (action . "Archive to persistent storage (optional)")) + ((step . 3) + (action . "Remove from in-memory zipper"))) + (limit . "1000 entries default, configurable"))) + +;;; =================================================================== +;;; EMERGENCY PROCEDURES +;;; =================================================================== + +(emergency-procedures + + ((name . "full-rollback") + (description . "Roll back all operations to session start") + (danger-level . :critical) + (steps + ((step . 1) + (action . "Confirm with user - this cannot be undone")) + ((step . 2) + (action . "Execute compensations from newest to oldest")) + ((step . 3) + (action . "Clear history zipper")) + ((step . 4) + (action . "Log full session for audit")))) + + ((name . "state-snapshot") + (description . "Capture complete system state for debugging") + (output . "Tarball with journal, history, and filesystem state"))) diff --git a/config/config.exs b/config/config.exs new file mode 100644 index 0000000..d367ef3 --- /dev/null +++ b/config/config.exs @@ -0,0 +1,32 @@ +# Valence Shell Configuration +# +# This file is loaded before any dependency and is restricted +# to this project only. + +import Config + +# General application configuration +config :valence, + # Sandbox root for file operations (safety boundary) + sandbox_root: System.get_env("VALENCE_SANDBOX") || "/tmp/valence", + + # History settings + history_limit: 1000, + journal_retention_days: 7, + + # Agent settings + default_agent_tier: 1, + agent_rate_limit: 60 # ops per minute + +# Logger configuration +config :logger, + level: :info, + format: "$time $metadata[$level] $message\n", + metadata: [:request_id, :idempotency_key] + +config :logger, :console, + format: "$time $metadata[$level] $message\n", + metadata: [:request_id, :idempotency_key] + +# Import environment-specific config +import_config "#{config_env()}.exs" diff --git a/config/dev.exs b/config/dev.exs new file mode 100644 index 0000000..a7c279d --- /dev/null +++ b/config/dev.exs @@ -0,0 +1,8 @@ +# Development configuration +import Config + +config :valence, + sandbox_root: "/tmp/valence-dev" + +config :logger, + level: :debug diff --git a/config/prod.exs b/config/prod.exs new file mode 100644 index 0000000..9d4e79e --- /dev/null +++ b/config/prod.exs @@ -0,0 +1,10 @@ +# Production configuration +import Config + +config :valence, + sandbox_root: System.get_env("VALENCE_SANDBOX") || raise("VALENCE_SANDBOX not set"), + history_limit: String.to_integer(System.get_env("VALENCE_HISTORY_LIMIT") || "1000"), + journal_retention_days: String.to_integer(System.get_env("VALENCE_JOURNAL_RETENTION") || "30") + +config :logger, + level: :info diff --git a/config/runtime.exs b/config/runtime.exs new file mode 100644 index 0000000..3362cf2 --- /dev/null +++ b/config/runtime.exs @@ -0,0 +1,10 @@ +# Runtime configuration (loaded at runtime, not compile time) +import Config + +if config_env() == :prod do + # Production runtime configuration + # These can be overridden by environment variables at runtime + + config :valence, + sandbox_root: System.get_env("VALENCE_SANDBOX") || "/var/lib/valence" +end diff --git a/config/test.exs b/config/test.exs new file mode 100644 index 0000000..7eaa712 --- /dev/null +++ b/config/test.exs @@ -0,0 +1,8 @@ +# Test configuration +import Config + +config :valence, + sandbox_root: "/tmp/valence-test" + +config :logger, + level: :warning diff --git a/hooks/pre-commit b/hooks/pre-commit old mode 100644 new mode 100755 diff --git a/justfile b/justfile index bde2344..6c3a11b 100644 --- a/justfile +++ b/justfile @@ -11,6 +11,14 @@ default: deps: mix deps.get +# Install git hooks (sacred file protection, contamination blocking) +install-hooks: + @./scripts/install-hooks.sh + +# Full setup: deps + hooks +setup: deps install-hooks + @echo "✅ Valence Shell ready for development" + # Create database (if using Ecto with backing store) db-setup: mix ecto.create @@ -206,6 +214,7 @@ help: @echo " Supervise /bin/sh, intercept reversible commands" @echo "" @echo "Common commands:" + @echo " just setup - Full setup (deps + hooks)" @echo " just deps - Fetch dependencies" @echo " just build - Compile project" @echo " just test - Run tests" diff --git a/scripts/install-hooks.sh b/scripts/install-hooks.sh new file mode 100755 index 0000000..19733fd --- /dev/null +++ b/scripts/install-hooks.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# Install Git hooks for Valence Shell +# +# Usage: ./scripts/install-hooks.sh +# +# This installs the pre-commit hook that: +# 1. Protects sacred files from accidental modification +# 2. Blocks Python/TypeScript contamination (RSR policy) + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(dirname "$SCRIPT_DIR")" +HOOKS_DIR="$REPO_ROOT/.git/hooks" +SOURCE_HOOK="$REPO_ROOT/hooks/pre-commit" + +echo "Installing Valence Shell Git hooks..." +echo "" + +# Check we're in a git repo +if [ ! -d "$REPO_ROOT/.git" ]; then + echo "❌ Error: Not a git repository" + exit 1 +fi + +# Check source hook exists +if [ ! -f "$SOURCE_HOOK" ]; then + echo "❌ Error: hooks/pre-commit not found" + exit 1 +fi + +# Create hooks directory if needed +mkdir -p "$HOOKS_DIR" + +# Install pre-commit hook +cp "$SOURCE_HOOK" "$HOOKS_DIR/pre-commit" +chmod +x "$HOOKS_DIR/pre-commit" + +echo "✅ Installed: pre-commit" +echo " - Protects sacred files (README.adoc, STATE.adoc, META.scm, ARCHITECTURE.md)" +echo " - Blocks Python/TypeScript contamination" +echo "" +echo "Hooks installed successfully!" +echo "" +echo "To uninstall: rm .git/hooks/pre-commit"