leopold-driver 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +19 -5
  2. package/assets/VERSION +1 -0
  3. package/assets/extensions/README.md +52 -0
  4. package/assets/extensions/gstack/extension.json +8 -0
  5. package/assets/extensions/gstack/manage.sh +68 -0
  6. package/assets/extensions/leopold/extension.json +8 -0
  7. package/assets/extensions/leopold/manage.sh +59 -0
  8. package/assets/extensions/ovmem/README.md +101 -0
  9. package/assets/extensions/ovmem/extension.json +8 -0
  10. package/assets/extensions/ovmem/install.sh +330 -0
  11. package/assets/extensions/ovmem/manage.sh +87 -0
  12. package/assets/extensions/ovmem/models.json +24 -0
  13. package/assets/extensions/ovmem/payload/RUNTIME.md +121 -0
  14. package/assets/extensions/ovmem/payload/ovmem-cleanup.py +148 -0
  15. package/assets/extensions/ovmem/payload/ovmem.py +421 -0
  16. package/assets/extensions/serena/README.md +50 -0
  17. package/assets/extensions/serena/extension.json +8 -0
  18. package/assets/extensions/serena/manage.sh +119 -0
  19. package/assets/hooks/guard-irreversible.sh +185 -0
  20. package/assets/hooks/hooks.json +20 -0
  21. package/assets/hooks/stop-continuity.sh +132 -0
  22. package/assets/install.sh +150 -0
  23. package/assets/scripts/__pycache__/leopold-watch.cpython-312.pyc +0 -0
  24. package/assets/scripts/leopold-doctor.sh +53 -0
  25. package/assets/scripts/leopold-menu.sh +132 -0
  26. package/assets/scripts/leopold-update-check.sh +23 -0
  27. package/assets/scripts/leopold-update.sh +13 -0
  28. package/assets/scripts/leopold-watch.py +585 -0
  29. package/assets/scripts/record-demo.sh +61 -0
  30. package/assets/scripts/test-guard.sh +76 -0
  31. package/assets/scripts/test-hooks.sh +121 -0
  32. package/assets/settings.template.json +23 -0
  33. package/assets/skills/leopold-brief/SKILL.md +121 -0
  34. package/assets/skills/leopold-doctor/SKILL.md +23 -0
  35. package/assets/skills/leopold-run/SKILL.md +171 -0
  36. package/assets/skills/leopold-status/SKILL.md +34 -0
  37. package/assets/skills/leopold-stop/SKILL.md +36 -0
  38. package/assets/skills/leopold-update/SKILL.md +27 -0
  39. package/assets/skills/leopold-watch/SKILL.md +48 -0
  40. package/assets/templates/CHARTER.md +32 -0
  41. package/assets/templates/DECISIONS.md +15 -0
  42. package/assets/templates/GUARDRAILS.md +38 -0
  43. package/assets/templates/MISSION.md +22 -0
  44. package/assets/templates/PLAN.md +9 -0
  45. package/dist/guard.js +82 -23
  46. package/dist/harness.js +71 -0
  47. package/dist/index.js +53 -23
  48. package/package.json +18 -6
package/README.md CHANGED
@@ -58,14 +58,26 @@ npm run build
58
58
 
59
59
  ## Usage
60
60
 
61
- From any project that already has a `.leopold/` brief (written by `/leopold-brief`),
62
- and with Claude Code logged in:
61
+ This package is the whole of Leopold from npm it bundles the harness (skills, hooks,
62
+ installer, extensions) so the CLI runs everything **without cloning the repo or `make`**.
63
+ The binary is exposed as both `leopold-driver` and `leopold`.
63
64
 
64
65
  ```bash
65
- node /path/to/leopold/packages/driver/dist/index.js # run
66
- node /path/to/leopold/packages/driver/dist/index.js --dry-run # load brief, show the plan, do nothing
66
+ npm i -g leopold-driver
67
+
68
+ leopold install # copy skills + hooks into ~/.claude (also: --with-gstack)
69
+ leopold menu # toolchain manager (serena / gstack / ovmem)
70
+ leopold watch [--port N] # live dashboard at http://127.0.0.1:4179 (needs Python 3)
71
+ leopold serena install # manage an extension directly (also: gstack, ovmem)
72
+ leopold doctor # run every extension's doctor
73
+ leopold update # reinstall from this package
74
+ leopold run [--dry-run] # conduct the .leopold run (the SDK driver below)
67
75
  ```
68
76
 
77
+ `watch` reads the current project's `.leopold/` and shows run status, cost meters, the
78
+ event feed, decisions, and a Stop button. `run` needs a `.leopold/` brief (from
79
+ `/leopold-brief`) and your Claude Code login.
80
+
69
81
  ### Environment
70
82
 
71
83
  | Var | Default | Purpose |
@@ -83,7 +95,9 @@ in-session engine.
83
95
  ## Status and known limits
84
96
 
85
97
  Alpha. Verified: compiles against `@anthropic-ai/claude-agent-sdk`, the CLI and
86
- dry-run work, the status parser and git guard are tested. Not yet built: a
98
+ dry-run work, and the status parser + `canUseTool` guard have unit tests
99
+ (`make driver-test` / `npm test`) covering the same bypass attempts as the bash
100
+ guard's red-team suite. Not yet built: a
87
101
  watchdog for a worker that ends a turn without emitting a status block (today the
88
102
  worker is strongly instructed to always emit one), parallel multi-worker waves,
89
103
  and the live dashboard. See the repo roadmap.
package/assets/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.4.3
@@ -0,0 +1,52 @@
1
+ # Leopold extension registry
2
+
3
+ The toolchain manager (`scripts/leopold-menu.sh`, or `make menu`) is data-driven: it
4
+ discovers everything under this directory and drives each one through a uniform contract.
5
+ This is the generalization of the one-off gstack prompt that used to live in `install.sh`.
6
+
7
+ ## Layout
8
+
9
+ ```
10
+ extensions/
11
+ <name>/
12
+ extension.json # metadata the menu renders
13
+ manage.sh # the actions the menu calls
14
+ README.md # optional, per-extension docs
15
+ ```
16
+
17
+ ## extension.json
18
+
19
+ ```json
20
+ {
21
+ "name": "gstack",
22
+ "title": "gstack",
23
+ "summary": "One-line description shown in the menu.",
24
+ "homepage": "https://...",
25
+ "license": "MIT",
26
+ "order": 20
27
+ }
28
+ ```
29
+
30
+ `order` controls position in the menu (lower first). Convention: Leopold core 10,
31
+ the toolchain it conducts 20, companion capabilities 30+.
32
+
33
+ ## manage.sh contract
34
+
35
+ `manage.sh <action>` where action is one of:
36
+
37
+ | action | must do | exit code |
38
+ |---------|---------|-----------|
39
+ | `detect` | nothing visible; just probe | `0` if installed, non-zero if not |
40
+ | `status` | print one short line (e.g. version/health) | `0` |
41
+ | `install` | install the component | `0` on success |
42
+ | `update` | update to latest | `0` on success |
43
+ | `remove` | uninstall (be reversible / safe where possible) | `0` on success |
44
+ | `doctor` | print diagnostics (what's wired, what's missing) | `0` |
45
+
46
+ Rules:
47
+ - Keep it idempotent. `install` run twice must not break anything.
48
+ - Never touch the user's git. Never print secrets.
49
+ - `detect` is the single source of truth for "installed?" — keep it cheap (no network).
50
+ - Resolve the Claude home as `${CLAUDE_HOME:-$HOME/.claude}`.
51
+
52
+ Adding a component is just dropping a new folder here with these two files.
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "gstack",
3
+ "title": "gstack",
4
+ "summary": "Garry Tan's planning + QA skill suite that Leopold conducts (/spec, /autoplan, /plan-*-review).",
5
+ "homepage": "https://github.com/garrytan/gstack",
6
+ "license": "MIT",
7
+ "order": 20
8
+ }
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env bash
2
+ # gstack extension - install/manage the gstack skill suite that Leopold conducts.
3
+ # gstack is a separate MIT project by Garry Tan: https://github.com/garrytan/gstack
4
+ set -euo pipefail
5
+
6
+ CLAUDE="${CLAUDE_HOME:-$HOME/.claude}"
7
+ SKILLS="$CLAUDE/skills"
8
+ GSTACK_DIR="$SKILLS/gstack"
9
+ REPO="https://github.com/garrytan/gstack.git"
10
+
11
+ case "${1:-}" in
12
+ detect)
13
+ # installed if the clone exists, or if its skills are already present
14
+ [ -d "$GSTACK_DIR" ] || ls "$SKILLS" 2>/dev/null | grep -q '^spec$'
15
+ ;;
16
+
17
+ status)
18
+ if [ -d "$GSTACK_DIR/.git" ]; then
19
+ echo "$(cd "$GSTACK_DIR" && git rev-parse --short HEAD 2>/dev/null || echo present)"
20
+ else
21
+ echo "present"
22
+ fi
23
+ ;;
24
+
25
+ install)
26
+ if [ -d "$GSTACK_DIR" ]; then
27
+ echo "gstack already installed at $GSTACK_DIR"
28
+ exit 0
29
+ fi
30
+ command -v bun >/dev/null 2>&1 || echo "note: gstack needs Bun v1.0+ (https://bun.sh); its setup will guide you."
31
+ echo "-> cloning gstack into $GSTACK_DIR (shows progress; a few seconds)"
32
+ mkdir -p "$SKILLS"
33
+ git clone --progress --single-branch --depth 1 "$REPO" "$GSTACK_DIR"
34
+ echo "-> running gstack setup"
35
+ ( cd "$GSTACK_DIR" && ./setup )
36
+ echo "gstack installed."
37
+ ;;
38
+
39
+ update)
40
+ if [ ! -d "$GSTACK_DIR/.git" ]; then
41
+ echo "gstack not installed as a git clone; nothing to update. Run install."
42
+ exit 0
43
+ fi
44
+ echo "-> pulling gstack"
45
+ ( cd "$GSTACK_DIR" && git pull --ff-only -q && ./setup )
46
+ echo "gstack updated."
47
+ ;;
48
+
49
+ remove)
50
+ if [ -d "$GSTACK_DIR" ]; then
51
+ rm -rf "${GSTACK_DIR:?}"
52
+ echo "removed $GSTACK_DIR"
53
+ else
54
+ echo "gstack not present."
55
+ fi
56
+ ;;
57
+
58
+ doctor)
59
+ echo "dir: $([ -d "$GSTACK_DIR" ] && echo "$GSTACK_DIR" || echo "missing")"
60
+ echo "bun: $(command -v bun >/dev/null 2>&1 && bun --version 2>/dev/null || echo "not found (needed for setup)")"
61
+ echo "spec skill: $([ -d "$SKILLS/spec" ] && echo present || echo missing)"
62
+ ;;
63
+
64
+ *)
65
+ echo "usage: manage.sh {detect|status|install|update|remove|doctor}" >&2
66
+ exit 2
67
+ ;;
68
+ esac
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "leopold",
3
+ "title": "Leopold",
4
+ "summary": "The autonomous orchestration harness itself (skills + Stop/PreToolUse hooks).",
5
+ "homepage": "https://github.com/Jonhvmp/leopold",
6
+ "license": "MIT",
7
+ "order": 10
8
+ }
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env bash
2
+ # Leopold core extension - manage the harness install (skills + hooks).
3
+ # install/update delegate to the canonical scripts so there is one source of truth.
4
+ set -euo pipefail
5
+
6
+ CLAUDE="${CLAUDE_HOME:-$HOME/.claude}"
7
+ LEO_HOME="$CLAUDE/leopold"
8
+ SKILLS="$CLAUDE/skills"
9
+
10
+ # Resolve this extension's own location to reach sibling scripts / VERSION,
11
+ # whether running from a clone (repo/extensions/leopold) or an install
12
+ # (~/.claude/leopold/extensions/leopold).
13
+ HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14
+ ROOT="$(cd "$HERE/../.." && pwd)" # repo root, or ~/.claude/leopold
15
+
16
+ case "${1:-}" in
17
+ detect)
18
+ [ -d "$LEO_HOME/hooks" ] && [ -d "$SKILLS/leopold-run" ]
19
+ ;;
20
+
21
+ status)
22
+ if [ -f "$ROOT/VERSION" ]; then echo "v$(cat "$ROOT/VERSION" 2>/dev/null | tr -d '[:space:]')"; else echo "installed"; fi
23
+ ;;
24
+
25
+ install|update)
26
+ if [ -x "$ROOT/install.sh" ]; then
27
+ bash "$ROOT/install.sh"
28
+ elif [ -x "$LEO_HOME/scripts/leopold-update.sh" ]; then
29
+ bash "$LEO_HOME/scripts/leopold-update.sh"
30
+ else
31
+ echo "no installer found (expected $ROOT/install.sh or $LEO_HOME/scripts/leopold-update.sh)"
32
+ exit 1
33
+ fi
34
+ ;;
35
+
36
+ remove)
37
+ echo "Removing Leopold core also removes this menu. Doing it by hand keeps you in control:"
38
+ echo " rm -rf $LEO_HOME"
39
+ echo " rm -rf $SKILLS/leopold-*"
40
+ echo " then remove the Stop + PreToolUse hooks from $CLAUDE/settings.json"
41
+ echo " (a backup was written to settings.json.leopold.bak at install time)"
42
+ ;;
43
+
44
+ doctor)
45
+ if [ -x "$LEO_HOME/scripts/leopold-doctor.sh" ]; then
46
+ bash "$LEO_HOME/scripts/leopold-doctor.sh"
47
+ elif [ -x "$ROOT/scripts/leopold-doctor.sh" ]; then
48
+ bash "$ROOT/scripts/leopold-doctor.sh"
49
+ else
50
+ echo "skills: $([ -d "$SKILLS/leopold-run" ] && echo ok || echo missing)"
51
+ echo "hooks: $([ -d "$LEO_HOME/hooks" ] && echo ok || echo missing)"
52
+ fi
53
+ ;;
54
+
55
+ *)
56
+ echo "usage: manage.sh {detect|status|install|update|remove|doctor}" >&2
57
+ exit 2
58
+ ;;
59
+ esac
@@ -0,0 +1,101 @@
1
+ # ovmem extension
2
+
3
+ **ovmem** gives Claude Code autonomous, self-managing long-term memory: it wires
4
+ [OpenViking](https://github.com/volcengine/OpenViking) (a hierarchical context DB) to
5
+ Claude Code through 4 native hooks, so any session stays optimized without destructive
6
+ `/compact` or `/clear`. Distillation, dedup and reconsolidation happen server-side; a
7
+ weekly hotness prune keeps the store from accumulating.
8
+
9
+ The installer is a **provider + model picker**. It runs `detect / status / install /
10
+ update / remove / doctor` like every extension; `install` walks you through:
11
+
12
+ ```
13
+ Provider: 1) openai 2) bedrock
14
+ chat model: gpt-4o-mini $0.15 in / $0.60 out per 1M · ctx 128k · cheap default
15
+ ...
16
+ embed model: text-embedding-3-small $0.02 per 1M · 1536d · default
17
+ ...
18
+ ```
19
+
20
+ Prices and the model lineup live in [`models.json`](models.json) — the single source the
21
+ picker reads (USD per 1M tokens, approximate, sourced from the LiteLLM price map). For
22
+ ovmem the real cost is **cents**: extraction only runs at PreCompact / SessionEnd.
23
+
24
+ ## Providers
25
+
26
+ ### OpenAI
27
+
28
+ One API key (needs the **embedding** and **`model.request`/chat** scopes). The installer
29
+ validates the key against both before saving it to `~/.openviking/ov.conf` (`chmod 600`).
30
+
31
+ - chat: `gpt-4o-mini` (default) · `gpt-4.1-mini` · `gpt-4o`
32
+ - embed: `text-embedding-3-small` (1536d, default) · `text-embedding-3-large` (3072d)
33
+
34
+ ### AWS Bedrock
35
+
36
+ Routed through OpenViking's LiteLLM backends. Auth is a **Bedrock API key (bearer token)**
37
+ plus a **region** — that is all the user passes. The installer:
38
+
39
+ - adds `boto3` to the OpenViking tool venv (`uv tool install --with boto3 …`),
40
+ - writes the bearer token + region into the server's launch env (`openviking-start`, `chmod 700`),
41
+ - sets `vlm.provider` / `embedding.dense.provider` to `litellm` with `bedrock/…` model ids.
42
+
43
+ - chat: `nova-lite` (cheapest) · `claude-3-5-haiku` · `claude-3-5-sonnet` · `claude-sonnet-4-5`
44
+ - embed: `titan-embed-v2` (1024d) · `cohere-embed-v3` (1024d) · `titan-embed-v1` (1536d)
45
+
46
+ > The chat model ids use the `us.` cross-region inference profile. The model must be
47
+ > **enabled in your AWS account** (Bedrock → Model access). The installer's round-trip
48
+ > step surfaces a clear error if access/region/token is wrong. The Bedrock path is
49
+ > implemented against OpenViking's verified config shape but has not been run against a
50
+ > live AWS account in CI — treat it as beta.
51
+
52
+ ## Switching providers / reconfiguring
53
+
54
+ Run `install` (or `update`) from the toolchain menu again — it is also the reconfigure
55
+ path. It detects the current setup, **offers to reuse the existing credential**, defaults
56
+ every prompt to your current choice, and:
57
+
58
+ - **Chat-only change** (or new model, same embedding) → just rewrites `ov.conf` and
59
+ restarts. Your memories are untouched.
60
+ - **Embedding change** (e.g. OpenAI → Bedrock, where the dimension goes 1536 → 1024) →
61
+ the vector index is **rebuilt**: it backs up and drops the index, lets the server
62
+ recreate it at the new dimension, then re-embeds every memory (`content/reindex`). Your
63
+ memory **content is preserved** — only the index is rebuilt. If the rebuild fails, the
64
+ previous index **and** config are restored automatically.
65
+
66
+ Server restarts are lock-aware (one OpenViking process per data dir — a kill+restart race
67
+ on the data-dir lock is exactly what breaks otherwise).
68
+
69
+ ## Notes that bite
70
+
71
+ - **The embedding model sets the vector dimension** (1536 / 3072 / 1024), baked into the
72
+ vectordb. Changing it is handled by the reindex above, but it re-embeds the whole store
73
+ (cents + a few seconds), so don't flip it casually.
74
+ - **`vlm.max_tokens`**: 16384 for OpenAI gpt-4o-mini (its cap), 8192 for Bedrock.
75
+ - **`output_language_override: "en"`** pins memory + summaries to English.
76
+
77
+ ## Headless / CI install
78
+
79
+ No terminal? Set the choices via env (the picker reads `/dev/tty` interactively, or these
80
+ when there is none):
81
+
82
+ ```bash
83
+ OVMEM_PROVIDER=openai OVMEM_CHAT_MODEL=gpt-4o-mini OVMEM_EMBED_MODEL=text-embedding-3-small \
84
+ OPENAI_API_KEY=sk-... bash install.sh
85
+ # or
86
+ OVMEM_PROVIDER=bedrock OVMEM_CHAT_MODEL=claude-3-5-haiku OVMEM_EMBED_MODEL=titan-embed-v2 \
87
+ AWS_BEARER_TOKEN_BEDROCK=... AWS_REGION=us-east-1 bash install.sh
88
+ ```
89
+
90
+ ## Runtime model (reference)
91
+
92
+ 4 hooks → OpenViking REST:
93
+ - **SessionStart** — bootstrap the server + rehydrate (session summary + long-term memory)
94
+ - **UserPromptSubmit** — recall: inject memory relevant to the prompt (token-budgeted)
95
+ - **PreCompact** — flush the transcript delta + commit *before* compaction destroys it
96
+ - **SessionEnd** — flush + commit, then the weekly hotness prune (`ovmem-cleanup.py`)
97
+
98
+ Dedup and obsolescence are handled natively by OpenViking on commit. Cold-memory
99
+ accumulation is pruned by `ovmem-cleanup.py` (hotness = frequency × recency decay).
100
+ Everything is local: the server binds `127.0.0.1` only. The lone outbound call is to the
101
+ chosen provider (OpenAI or Bedrock, with the user's own credential) for embeddings/extraction.
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "ovmem",
3
+ "title": "ovmem",
4
+ "summary": "Autonomous RAG long-term memory (OpenViking + 4 hooks). Provider + model picker (OpenAI / AWS Bedrock) with prices.",
5
+ "homepage": "https://github.com/Jonhvmp/leopold",
6
+ "license": "MIT",
7
+ "order": 30
8
+ }