Skip to main content

diagit

AI Cost Tracking

PyPI Version Python License AI Cost Human Time Model

  • 🤖 LLM usage: $0.4305 (15 commits)
  • 👤 Human dev: ~$727 (7.3h @ $100/h, 30min dedup)

Generated on 2026-08-10 using openrouter/qwen/qwen3-coder-next


diagit is a read-only-by-default auditor for a fleet of Git repositories laid out as ROOT/owner/repository, for example /home/tom/github/*/*.

It records immutable protobuf events, builds a disposable SQLite CQRS read model, and exposes a small allowlisted diagit:// process URI catalog. It never fetches, checks out, commits, pushes, or repairs a repository during an audit. Separate control plans require a digest-bound authority grant and independent read-back validation.

Install and run

python -m pip install -e '.[test]'
diagit audit --root ~/github
diagit audit --root ~/github --organization subactor \
  --repository 'subactor/*-agent' --exclude-repository 'subactor/*-worktree'
diagit audit --root ~/github/semcod --repository todo2code
diagit audit --root ~/github/semcod --layout organization
diagit query summary
diagit query findings --severity SEVERITY_CRITICAL
diagit query repo subactor/core
diagit diagnostics list
diagit diagnostics show DIRTY_WORKTREE
diagit uri 'diagit://fleet/query/summary'
diagit remote audit --organization subactor
diagit remote summary --organization subactor
diagit plan governance --organization subactor --output governance.json
diagit plan repairs --organization subactor --output-dir repair-plans
diagit plan fleet-repairs --organization subactor \
  --repository 'subactor/*-agent' \
  --exclude-repository 'subactor/*-worktree' \
  --code OPENROUTER_APP_IDENTITY_MISSING --output-dir openrouter-repairs
diagit plan governance --organization legacy-org \
  --rename-default-to-main --archive-unmerged --output governance.json
diagit onedev status \
  --onedev-password-file /path/to/onedev-admin-password
diagit forge audit --max-items 1000
diagit forge recommend --require actions --require projects \
  --visibility private --prefer-self-managed
diagit grammar
diagit dsl --expression '```diagitdsl
QUERY SUMMARY
```'
diagit shell
diagit serve --root ~/github --bind 127.0.0.1 --port 8765

The default state directory is $XDG_STATE_HOME/diagit, or ~/.local/state/diagit. Override it with --state-dir or DIAGIT_STATE_DIR.

An audit root may be the fleet directory (ROOT/owner/repository) or one organization directory (ROOT/repository). Repository selectors containing / match the canonical owner/repository ID; selectors without / match the bare repository name. Both forms accept shell-style globs.

--layout auto is the default. Use --layout fleet or --layout organization when a root contains both direct worktrees and organization directories. A selected candidate whose Git marker cannot be read remains visible as a typed PROBE_FAILED result instead of disappearing from audit coverage.

Operator service

Running diagit without a subcommand starts the operator service. From ~/github it discovers every organization that contains Git worktrees. From ~/github/<organization> or any repository below it, it limits the initial scope to that organization. The initial local audit starts immediately and reports progress for every completed repository.

In a terminal, the service remains active and accepts single-key shortcuts without Enter:

a  repeat the local audit
r  audit selected GitHub organizations and compile repair planfiles
d  explicitly approve and delegate the prepared plans to OneDev
s  select one organization or the complete detected scope
q  exit cleanly

Delegation requires an additional y confirmation. Diagit then creates a mode-0600, ten-minute authority grant for each exact plan digest and submits only CONTROL_ACTION_SUBMIT_REPAIR; Doctor/Repair/Validator evidence remains mandatory. When stdin is not a TTY, the same bare invocation performs one bounded local audit, prints progress, and exits instead of waiting for input.

Diagnostic registry

Every finding keeps its concise compatibility code, such as DIRTY_WORKTREE, and is enriched from the packaged diagit.diagnostic-registry/v2 catalog with a stable identifier such as DIAGIT-GIT-003, category, severity, error class, retryability, and an optional repair URI. The registry is the source of truth: emitting an unknown code or a severity/message that differs from its definition fails closed.

The four severities have consistent operational meaning: INFO records useful state, WARNING requires planned attention, ERROR blocks the requested invariant, and CRITICAL means the audit or control boundary itself is not trustworthy or available.

Remote pull requests are classified independently of the generic OPEN_PULL_REQUEST finding. The registry distinguishes green mergeable PRs, failed, pending or missing checks, merge conflicts, unknown mergeability, and drafts stale for at least 30 days. A green unmerged PR is always emitted as PR_GREEN_REQUIRES_MERGE and cannot be archived by the governance cleanup policy.

Architecture

  • Commands change only the auditor's own state. AuditFleet observes Git repositories and appends AuditRunStarted, RepositoryAudited, and AuditRunCompleted protobuf events.
  • The length-delimited events.pb file is the canonical event store. New Protobuf events form a deterministic SHA-256 chain and retain read compatibility with legacy version 1 history.
  • Queries read a rebuildable SQLite projection (projection.sqlite3).
  • Forge account observations from GitHub, GitLab, Gitea/Forgejo, and Bitbucket are stored as ForgeAccountTwinObserved protobuf events. Their read model ranks providers from visible scopes, repositories, capabilities, visibility, completeness, and self-managed preference; it never reads repository content. The canonical contract and reviewed decision baseline are pinned to uri-twin/uri-twin-forge; Diagit returns that source revision with each audit and recommendation.
  • diagit rebuild recreates the projection solely from stored events.
  • URI processes are explicit adapters to the same command/query handlers; an arbitrary URI can never become a shell command.

The canonical GBNF request language maps to the same CQRS messages as CLI, shell, process URI, and loopback REST. Its Wellmanifest contract binds the grammar, parser, storage schema, examples, command documentation, errors, and critical security pages by SHA-256. See docs/DSL_ARCHITECTURE.md and dsl-manifest.json.

DSL and API

Every DSL request is exactly one fenced statement:

```diagitdsl
QUERY FINDINGS CODE "*" SEVERITY "SEVERITY_ERROR" LIMIT 1000 OFFSET 0
```

LIMIT is deliberately bounded to 1000. Fleet controllers must increment OFFSET until the returned page is shorter than the requested limit; values are never silently truncated.

The REST adapter binds only to loopback and exposes GET /health, GET /v1/grammar, CQRS query routes, bounded command routes, and POST /v1/dsl. It does not expose GitHub control-plan application. The interactive shell accepts the inner statement without Markdown fencing but sends it through the same GBNF parser.

Command help: AUDIT, REBUILD, SUMMARY, FINDINGS, and REPOSITORY.

Error help: DIAGIT-REQUEST-INVALID, DIAGIT-NOT-FOUND, DIAGIT-ROOT-ESCAPE, and DIAGIT-EVENT-INTEGRITY.

Supported URI processes:

diagit://fleet/audit?root=/home/tom/github
diagit://fleet/query/summary
diagit://fleet/query/findings?severity=SEVERITY_WARNING&limit=100
diagit://repository/<owner>/<repo>/query/report
diagit://projection/rebuild
diagit://github/<organization>/audit
diagit://github/<organization>/query/summary
diagit://forge/audit?providers=github,gitlab,gitea,bitbucket&max_items=1000
diagit://forge/query/recommend?requires=actions,projects&visibility=private&prefer_self_managed=true

Governed control plans

Remote audit observations can be compiled into the versioned diagit.control-plan/v1 JSON DSL. Every executable plan embeds a subactor.process-envelope.v2 with all four governed definitions: AQL authority, transport-independent OQL operations, exact URI processes, and EQL expectations. A governance plan closes an open pull request or deletes an extra branch only when the branch head is already contained in main. By default, unmerged branches remain blockers. The explicit --archive-unmerged policy first creates and independently validates a deterministic diagit/archive/<branch>-<sha> tag, then permits branch deletion and PR closure through dependent URI steps. --rename-default-to-main safely migrates a default branch only when main does not already exist and the observed head SHA still matches.

Applying a plan requires a separate mode-0600 diagit.authority-grant/v1 file. The grant must name the organization and allowed action kinds, bind the exact plan SHA-256 digest, identify its approver, and have a future expiry. Execution is explicit:

diagit apply governance.json \
  --authority-file authority.json \
  --confirm-apply

An archived branch can be restored through a separately authorized plan:

diagit plan restore --repository owner/repository --branch fix/recover \
  --tag diagit/archive/fix/recover-0123456789ab \
  --expected-head 0123456789abcdef0123456789abcdef01234567 \
  --output restore.json

For code repair, generate a single OneDev handoff action. The instruction is data, never a command:

diagit plan repair \
  --repository subactor/core \
  --task-id 0004_node-domain-tickets \
  --instruction-file repair-instruction.txt \
  --output repair.json

Before applying an action, Diagit fails closed unless its AQL actor explicitly allows the matching OQL operation and the action is bound to exactly one URI step. After an authorized apply, Diagit sends the complete envelope, canonical plan digest, grant ID, and approving principal to the existing OneDev Agent /tasks/execute boundary. OneDev independently repeats the AQL/OQL/URI/EQL checks before materializing a Planfile ticket. OneDev then owns Doctor → Repair → Validator, test gates, exact-SHA checks, and publication. A submission receipt remains submitted; only validator evidence can satisfy the terminal EQL. The referenced diagit-repair-delegation.pl.aql decision model is packaged with the wheel, so the envelope never relies on an unresolved model name.

diagit plan repairs compiles the latest remote audit into one independently authorizable plan per affected repository plus a diagit.repair-plan-set/v1 manifest. It selects only diagnostics whose registered repair URI delegates to OneDev, deduplicates them into a bounded instruction, and preserves the source audit run ID. --code can be repeated to restrict generation to specific delegable diagnostic codes. Generating the set never submits work; each plan still requires its own digest-bound authority grant before diagit apply can cross the OneDev boundary.

diagit audit accepts repeatable exact or glob repository selectors. The fleet-repairs variant compiles local findings from the latest completed audit, so one diagnostic becomes an independently authorized OneDev ticket for each selected repository rather than one unbounded fleet mutation.

OpenRouter application attribution

DIAGIT-LLM-001 / OPENROUTER_APP_IDENTITY_MISSING identifies tracked runtime consumers of OpenRouter that do not provide verifiable cost attribution. A compliant repair declares OPENROUTER_APP_NAME and OPENROUTER_APP_URL in the environment template and binds them to X-OpenRouter-Title and HTTP-Referer. When the name is blank, runtime code must use the repository directory name. Environment templates and policy implementations are not consumers by themselves. Applications routed through subllm receive provider identity from its central application/function policy and do not duplicate this local binding. Diagit reads only variable names and bounded tracked source files; finding evidence never contains environment values or API keys.

The audit uses only local Git metadata. Ahead/behind values therefore describe the locally known upstream refs and do not imply a network refresh.

Release readiness

diagit audit --root ~/github --organization subactor --check-registries adds bounded release checks to the normal event-sourced fleet audit. Local checks validate goal.yaml, package file boundaries, and version tags. Registry checks compare public package.json and pyproject.toml manifests with npm and PyPI; Node packages with private: true are never treated as publication candidates.

The command is read-only: it reports unpublished packages and version drift but never publishes, tags, or pushes. Registry access is opt-in because it requires network I/O.

Development

python -m grpc_tools.protoc -Iproto --python_out=src --pyi_out=src proto/diagit/v1/audit.proto
scripts/verify
scripts/verify-dsl

The package distribution name is diagit, its Python import is diagit, and its executable is diagit (which also permits the Git external-command form git diagit).

License

Licensed under Apache-2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

diagit-0.10.1.tar.gz (94.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

diagit-0.10.1-py3-none-any.whl (83.5 kB view details)

Uploaded Python 3

File details

Details for the file diagit-0.10.1.tar.gz.

File metadata

  • Download URL: diagit-0.10.1.tar.gz
  • Upload date:
  • Size: 94.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.12

File hashes

Hashes for diagit-0.10.1.tar.gz
Algorithm Hash digest
SHA256 2dcc1e128ab4dea34987a1fc9b708cd5d12c39bcad5e5b24012341802fea1b34
MD5 11ca21046e966af548b24c7c4a53a15d
BLAKE2b-256 67ae98c1d019591338ee37134cd2dcd94caf659aee7eb03da519d4c6ddc3b1ca

See more details on using hashes here.

File details

Details for the file diagit-0.10.1-py3-none-any.whl.

File metadata

  • Download URL: diagit-0.10.1-py3-none-any.whl
  • Upload date:
  • Size: 83.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.12

File hashes

Hashes for diagit-0.10.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f45ee635965b4c4a7473bc39095e2d9af5182625b8a918a04834244267f19367
MD5 9df91cad054a4d38afc44e1f2a1a29c4
BLAKE2b-256 5cc757c653884099e332e4ebbe1b1546fae6fb77bff17959bf35ce5361f57bef

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.10.1 This release

2 files

0.10.0

2 files

0.9.1

2 files

0.9.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page