Skip to content

feat: Jeli Phase 1 — core primitives, Scoped MCP tools, stdio server#1

Merged
jp-cruz merged 5 commits into
mainfrom
feat/phase1-scoped-mcp
Jul 2, 2026
Merged

feat: Jeli Phase 1 — core primitives, Scoped MCP tools, stdio server#1
jp-cruz merged 5 commits into
mainfrom
feat/phase1-scoped-mcp

Conversation

@jp-cruz

@jp-cruz jp-cruz commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Publishes the local Phase 1 work as a single squashed, scrubbed commit onto the repo's published history. (Local dev history predates the privacy-scrubbed re-push of this repo and is intentionally not carried over; an internal repo-audit doc and vault-path references were scrubbed from the docs.)

What's here

Core primitives (from the local Phase 1 baseline, 99 tests):

  • core/hash_chain.py — HMAC-SHA256 chain, canonical records, chain validation, amendment tracking
  • core/trust_score.py — trust model (user-stated 1.0 … external 0.3), decay/boost/penalty
  • core/contradiction.py — direct / temporal / semantic / trust-conflict detection
  • security.py — injection defense (MINJA-derived patterns), timing-safe key validation
  • asyncpg pool, OpenAI+Ollama embedding providers, alembic 001 schema

New: the Scoped MCP surface (the first-priority deliverable from CLAUDE.md — until now no agent could reach any of this):

Tool Behavior
capture_memory sanitize → trust-validate → embed → hash-chain → append + audit row
search_memory read-only, valid rows only, trust-then-recency ranked, per-hit audit
audit_trail provenance + single-record integrity verification
verify_chain full oldest→newest HMAC walk; returns first tampered record

Security decisions

  • Injection-like content is never blocked — it's evidence. Capped at external-grade trust (0.3) and flagged for the judicial layer.
  • Actor identity is server-side config (SCOPED_MCP_AGENT_ACTOR), not a tool argument — agents cannot impersonate writers in the audit log.
  • SCOPED_MCP_CHAIN_KEY required at startup; verify_chain treats walk position as authoritative so a forged first record claiming an arbitrary prev_hash fails.

Tests

119 passing (20 new over an in-memory pool fake: chain linkage, tamper via content edit / reorder / forged hash without key, trust capping, audit rows). Coverage 74%.

Follow-ups

pgvector migration + semantic mode · write-path contradiction detection (Phase 3) · summarize_session · HTTP transport

🤖 Generated with Claude Code

Squashed re-publication of local Phase 1 work onto the repo's published
history (local dev history predates the repo's privacy-scrubbed re-push
and is intentionally not carried over).

Core (from local Phase 1 baseline):
- core/hash_chain.py: HMAC-SHA256 chain, canonical records, validators,
  amendment tracking
- core/trust_score.py: trust model (user 1.0 … external 0.3), decay,
  confirmation boost, contradiction penalty
- core/contradiction.py: direct/temporal/semantic/trust-conflict detection
- security.py: injection defense, timing-safe API key validation
- database/pool.py (asyncpg), embedding/provider.py (OpenAI + Ollama),
  alembic 001 schema (memory_entry, memory_audit_log, memory_contradiction)

New in this change:
- tools/memory_tools.py: capture_memory / search_memory / audit_trail /
  verify_chain — the scoped agent surface (no shell, no files, no raw SQL)
- server/mcp_server.py: stdio transport via official mcp SDK; server-side
  actor identity (agents cannot impersonate writers)
- injection-like content capped at external-grade trust (0.3) + flagged,
  never blocked
- config: SCOPED_MCP_CHAIN_KEY (required), SCOPED_MCP_AGENT_ACTOR
- alembic 002: embedding UUID placeholder -> JSONB (pgvector later)
- tests: 119 passing, coverage 74%

Co-Authored-By: Claude Fable 5 <[email protected]>
- .github/workflows/ci.yml: lint/test/sast/audit/secrets/sbom via
  dev-rig reusable workflows (coverage gate 70%)
- .github/workflows/lint-workflows.yml + .github/zizmor.yml: zizmor on
  workflow changes; hash-pin policy, first-party ref-pin allowance
- src/jeli_scoped_mcp/cli.py: 'jeli verify' — full-chain HMAC walk,
  exit 0/1/2, --json mode; runs without API key or embedding provider
  (MemoryTools embedder now optional; write path guards)
- .githooks/pre-push: scans every commit being pushed (not just the
  tree) for LAN IPs / ssh user@host / key paths / home paths; enable
  with 'git config core.hooksPath .githooks' (2026-07-02 incident)
- lint debt cleared for CI gates: ruff clean, mypy clean (16 files),
  bandit clean

124 tests passing, coverage 74%.

Co-Authored-By: Claude Fable 5 <[email protected]>
@jp-cruz

jp-cruz commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Pushed a second commit extending this PR: dev-rig CI wiring (lint/test/sast/audit/secrets/sbom + zizmor workflow linting — jeli was the only public LegionForge repo with no CI), the jeli verify CLI (full-chain HMAC walk, exit 0=valid / 1=broken / 2=misconfig, --json mode, runs read-only without API key or embedder), and .githooks/pre-push — the history-scrub hook from today's incident (scans every commit being pushed, not just the tree; enable per-clone with git config core.hooksPath .githooks). The hook blocked its own first push by matching its pattern definition, which was a satisfying live test. 124 tests, ruff/mypy/bandit clean.

@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

jp-cruz and others added 3 commits July 2, 2026 05:12
Same pattern as guardian: dummy keys in tests trip generic-api-key;
dev-rig lint job expects bandit installed via .[dev].

Co-Authored-By: Claude Fable 5 <[email protected]>
…l format final)

The canonical hashed form is the one thing that cannot change cheaply
after real data exists, so both format changes land together, pre-v0.1:

- key_id names the chain key that signed each record and lives INSIDE
  the hash — a record cannot be re-pointed at a weaker/compromised key
  without breaking its own hash. Enables per-record key rotation and
  the OpenBAO transit path (vault key versions). Registry: key_id ->
  key material; verification uses each record's own key; unknown
  key_id fails closed.
- trust_score canonicalizes to integer hundredths (0.6 -> 60) so
  float/Decimal round-trips through the DB can never alter a hash.
- alembic 003: key_id column (server_default 'k1') + index.
- config SCOPED_MCP_CHAIN_KEY_ID (default k1), wired through server
  and CLI.
- 3 new tests: verification across rotation, fail-closed on unknown
  key, key_id tamper-evidence. 127 passing.

Co-Authored-By: Claude Fable 5 <[email protected]>
@jp-cruz

jp-cruz commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Third commit set: canonical format finalized pre-v0.1key_id now lives inside every record's hash (per-record key rotation, OpenBAO-transit-ready, anti-downgrade: re-pointing a record at another key breaks its hash; unknown key_id fails closed) and trust canonicalizes to integer hundredths so float/Decimal round-trips can never alter a hash. Alembic 003 adds the column; SCOPED_MCP_CHAIN_KEY_ID wired through server + CLI. 3 new rotation/tamper tests → 127 passing. README gained Quick Start + configuration table + hook setup. Rationale thread in today's session notes.

@jp-cruz jp-cruz merged commit 185f481 into main Jul 2, 2026
12 checks passed
@jp-cruz jp-cruz deleted the feat/phase1-scoped-mcp branch July 2, 2026 21:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants