A read-only project-management view over many independent workstreams. Each workstream is a repository with its own AI agent and its own work queue. nemik shows who is working on what, how the work depends on other work, and how much effort goes to planned work versus interrupts, with interrupts tracked in the same dependency graph as the planned work.
nemik builds on existing standards rather than inventing a tracker:
- OSLC Change Management 3.0. Each queued item is an
oslc_cm:ChangeRequest. - W3C PROV. Each ledger entry is a
prov:Activitythat used a waypoint. What caused a waypoint isprov:wasInformedBy. - SHACL. The rules a queue must satisfy are SHACL shapes, checked by
nemik-check. - Prometheus / OpenTelemetry-style metrics for effort over time.
ForgeFed/ActivityPub is the intended model for the messages between workstreams: letters, asks and interrupts as Activities. It is designed but not yet implemented; see docs/model.md.
nemik never parses queue files itself. It reads them through
mikemol-pathsforward, the one owner
of the format:
| Source | Read through | Becomes |
|---|---|---|
<repo>/.claude/paths-forward.json |
store.load |
waypoints, enables edges, blockers |
<repo>/.claude/paths-forward.ledger |
ledger.read |
PROV activities, effort class |
~/.local/state/nemik/events.jsonl |
the global hook in hooks/ |
prompts by source |
| Command | What it does |
|---|---|
nemik-check |
Validates every queue against src/nemik/data/shapes.ttl. Exits 1 on a sh:Violation (a dangling edge, a duplicated symbol, or an unreadable queue). Warnings, such as vocabulary divergence, are printed and do not fail. |
nemik-metrics |
Prints Prometheus text: waypoints by state, findings, prompts and ledger lines by effort class. |
nemik-inbound [repo] |
What in other workstreams is blocked on repo, each blocked waypoint as a citable <repo>:W<n>, and which of repo's waypoints claims it, or UNCLAIMED. |
nemik-operator |
Blocks on the operator, sorted into needs-you, answered, condition and unstated, with duplicate asks grouped. |
nemik-wake |
The wake roster: each workstream something is waiting on, with whether it has a live session (asleep / idle / awake), what waits on it, and how many blocks need you. Liveness comes from luthen-observability's loop_liveness. |
nemik-rank repo |
Ready items by cross-repo downstream weight; --all (no repo) ranks every workstream's ready items in one composed order, so weight and key compare across repos (each row carries repo and cite, <repo>:W<n>); --check exits 1 when the queue's next item is outweighed or breaks a guarantee declared in bands.toml (a band INVERSION below the floor, or a POLICY block by an open trust-boundary item on a shared surface), naming the pair, and prints an UNSCORED census; --json feeds mikemol-paths-forward --weights-from. |
nemik-floor-asks |
Exits 1 when a summit/floor/*.bib ask's waypoint field names a missing or dropped waypoint. |
nemik-serve |
The web view: / (dependency graph), /graph.json, /graph.ttl, /inbound/<repo>, /operator, /wake, /metrics. |
.venv is the venv Bazel builds (bazel build //:.venv), the same one every test runs under;
rebuild it after a source or lock change, and never uv sync into it (nemik:W101).
The root defaults to ~/github and can be set with $NEMIK_ROOT or --root. It accepts
<root>/<repo>/.claude/paths-forward.* or a flat export, <root>/<repo>/paths-forward.*.
$ ./setup.sh # arms the pre-commit gate (W92); .venv -> bazel-bin/.venv (W104)
$ .venv/bin/nemik-check
$ .venv/bin/nemik-serve --port 8750nemik pins mikemol-pathsforward to its vendored wheel, and uv carries that pin into any project
that depends on nemik by path. A project that pins pathsforward itself will then fail to lock,
because uv refuses two sources for one package. The consumer's own pin should win, so declare it
as an override as well as a dependency (nemik:W51):
[project]
dependencies = ["nemik", "mikemol-pathsforward @ git+https://github.com/mikemol/mtools.git@<sha>#subdirectory=pathsforward"]
[tool.uv.sources]
nemik = { path = "../nemik" }
[tool.uv]
override-dependencies = ["mikemol-pathsforward @ git+https://github.com/mikemol/mtools.git@<sha>#subdirectory=pathsforward ; python_full_version >= '3.13'"]Keep the marker if your project supports Python below 3.13. Overrides apply to every Python version your project resolves for, and pathsforward itself requires 3.13 or later, so without the marker the lock fails for the older versions (summit 3abbe17).
Checked with summit's pin, fc74848, which is older than nemik's: uv lock resolves, and
nemik-check and nemik-floor-asks both run.
hooks/record_event.py is meant to run as a global Claude Code hook on UserPromptSubmit,
Stop and SessionStart. For each event it appends one line to a local spool: the time,
session, cgroup scope, repo, event, and where a prompt came from (a scheduled tick, an
operator-typed tick, the operator, a peer session, a subagent, or a background notice). It never
stores prompt text, never uses the network, and always exits 0.
mikemol-pycheck --install <draft> <dest.py>: formats a Python draft, runs the edit gate's ruff and mypy on it, and writes it to the destination only when it passes (a refused draft leaves no file), so a change that touches several places lands clean in one step (the edit gate refuses a half-formatted or half-imported file). It replaces tools/pyfmt.sh, which wrote first and left the dirty file.mikemol-repin --revendor --sha <40-hex> --no-sync --write: rebuilds the six vendored mtools wheels at one commit and rewrites the pins, the lock and the checksums (seevendor/wheels/README.md; it replaced the hand script tools/revendor-mtools.sh, mtools:W1449). Dry-run without--write;--no-synckeeps the bazel-built.venvas it is.- Before a submit, the ratchets the gate runs, locally:
PYTHONPATH=src .venv/bin/mikemol-pycheck --ratchet .(about a minute, printsruff: N findings, baseline Mand the same for mypy; exit 4 names each rise, 7 means nothing was judged; mtools:W1485/W1794, nemik:W536).mikemol-pycheck --changed .judges each file alone and does not compare against the baselines, which is where new files fail (a new file's baseline is 0).mikemol-websubset --check-file F --target codonanswers the Codon census rules for one file in seconds. tools/render-check.sh: the render check as a host step:tests/test_layout.pydrives the web view in the host's Google Chrome (layout budgets, the rank forest, repo toggles, salience order) and leaves screenshots in/var/tmp/nemik-shots. The Bazel gate stays hermetic, where the same tests skip.- Before committing:
bazel build //:.venv --show_result=0if a module was added, then the pre-commit gate (.githooks/pre-commit) runsbazel test //...; a push to main ships.
Containerfile builds the web view. Mount only the flat queue export read-only at /export,
not a whole source tree.