ArghDA is a lightweight proof-workspace manager. Initial target:
Agda. It exists to close a specific user-experience gap that
agda-mode and agda-language-server do not: making the
lifecycle of a proof (inbox → working → proven | rejected) a
first-class, visible object, with a thin linter that catches the
silent-failure class before the typechecker.
Scope discipline: small tool, narrow job. Not a proof assistant,
not a replacement for agda-mode, not a tactic framework.
From echo-types sessions (see docs/buchholz-plan.adoc), the
operator repeatedly hit a specific failure mode:
-
a proof file exists, looks like it typechecked, but is missing
--safe/--without-K, or is not imported fromAll.agda, or is not pinned inSmoke.agda -
the "did it really work?" question is answered only by running the whole suite, which is slow and emotionally punishing
-
there is no visible pipeline: no inbox, no "in-progress", no "proven" tag; just a flat directory of
.agdafiles
The existing ecosystem (see ArghDA scout report: coq-lsp,
VSCoq, Alectryon, LeanInk, Mathlib stats, Isabelle/jEdit
PIDE, agda-language-server, agda-unused) gives excellent
per-file UX and some library-level dependency views, but nobody
treats proofs as items flowing through pipeline stages. That is
the novel contribution.
Two layers, developed and published as two packages:
arghda-core-
Language-agnostic engine. Rust. No UI. Exposes a CLI, a library API, and a JSON event stream. Runs in CI, standalone, or embedded.
arghda-panll-
PanLL presentation layer. Gossamer webview
ReScript panel consuming `arghda-core’s event stream. Lives in the PanLL surface, probably adjacent to Pane-W.
Rationale for the split:
-
Proof triage is useful outside PanLL (students, CI, large collabs).
-
Testing
arghda-coredoesn’t require booting PanLL. -
PanLL gains a polished dependency rather than an internal subsystem.
-
Matches PanLL’s existing pattern with
panll_beam.
Four states, implemented as four directories under a workspace root:
<workspace>/
inbox/ -- new or returning proof files
working/ -- operator has picked this up
proven/ -- typecheck + lint clean
rejected/ -- typecheck failed, or lint-block, or manual rejectTransitions are file moves. This keeps the ground truth on disk,
makes recovery obvious (mv it back), and survives ArghDA crashing.
Transition rules:
| From | To | Trigger |
|---|---|---|
inbox |
working |
operator claim (explicit) |
working |
proven |
typecheck clean AND lint clean |
working |
rejected |
typecheck failed OR lint-hard-block |
rejected |
inbox |
manual re-queue |
proven |
inbox |
upstream change invalidates (see DAG below) |
Every transition emits a JSON event to a rolling log under
<workspace>/.arghda/events.jsonl.
The linter targets the silent-failure class — cases where Agda appears to succeed but the file is not actually in the verified suite. Rules, each emitting a structured diagnostic:
-
missing-safe-pragma— file lacks{-# OPTIONS --safe --without-K #-} -
missing-without-k—--safewithout--without-K(or vice versa) -
orphan-module— module not imported (transitively) fromAll.agda -
unpinned-headline— module exports a theorem matching a headline-naming pattern (operator-configurable regex) but the name is not pinned inSmoke.agdavia ausingclause -
unjustified-postulate—postulateblock without an adjacent comment line starting with-- JUSTIFY: -
unused-import— shell out toagda-unusedand re-emit findings -
tab-mix— file mixes tabs and spaces at line start
Severity: hard-block (forbids working → proven) vs warn
(surfaced but non-blocking). Default: missing-safe-pragma,
orphan-module, unjustified-postulate are hard-block; the rest
are warn.
Non-goals for v0: semantic linting, redundancy detection, style-guide enforcement beyond whitespace.
Emitted by arghda-core dag as a single JSON document. Consumable by
the PanLL panel, a static HTML viewer, or third-party tools.
{
"version": "0.1",
"workspace": "/path/to/workspace",
"generated_at": "ISO-8601",
"nodes": [
{
"id": "Ordinal.Closure",
"file": "proofs/agda/Ordinal/Closure.agda",
"status": "proven",
"lint": { "hard_block": [], "warn": [] },
"headlines": ["C-monotone"]
}
],
"edges": [
{ "from": "Ordinal.Closure", "to": "Ordinal.Base", "kind": "imports" }
],
"blocked": [
{
"node": "Ordinal.Buchholz.Psi",
"blocked_by": ["Ordinal.Buchholz.Closure"],
"reason": "prereq not proven"
}
]
}Renderer is a separate concern; the panel consumes this verbatim.
-
LSP (coq-lsp pattern) — per-file editor feedback.
-
PIDE async model (Isabelle) — asynchronous document state for the "checking now" sub-state within
working. -
agda --only-scope-checking— cheap pre-pass for quick syntactic / import validation before full typecheck. -
agda-unused— shell out; re-emit diagnostics in the ArghDA diagnostic format. -
Alectryon-style rendering (future) — static HTML render of proof states as a by-product of
proventransition.
-
Tactic language.
-
Writing proofs for the operator.
-
IDE replacement.
-
Multi-prover support (Coq/Lean/Isabelle postponed to v0.2).
-
Distributed execution. A single workspace, a single machine.
Ordered by unblock-value:
-
arghda-coreRust crate skeleton;Workspace::open(path)API. -
Filesystem watcher over
inbox/andworking/usingnotify. -
Two linter rules:
missing-safe-pragma,orphan-module. -
arghda-core check <file>command: runs agda, captures exit code, emits aLintReportJSON. -
arghda-core promote <file>/arghda-core reject <file>: the state-machine CLI. -
arghda-core dagemitting the schema above for the current workspace. -
Minimal end-to-end smoke test over
echo-typesitself as the first real workspace.
PanLL panel (arghda-panll) is v0.2 and deliberately not in this
sprint. The CLI + JSON is the interface contract; the panel is a
consumer.
-
Language choice for
arghda-core: Rust (matches PanLL stack) vs Zig (matches Gossamer / Burble). Default: Rust, pending operator pushback. -
Should the
provenstate record a content hash so upstream changes can invalidate it automatically? Default: yes, SHA-256 of the file plus imports. -
Naming convention for "headlines" — regex default
^[a-z][A-Za-z0-9-]*$with export-only filter, operator-overridable per-workspace in.arghda/config.toml.
-
End-to-end demo: take
echo-typesat its current commit, place all*.agdafiles intoinbox/, runarghda-coreagainst it, observe that every file moves toproven/with no hard-blocks, and that the emitted DAG matches the actual import graph. -
Introduce one synthetic bug (delete
--safefrom a file): observe that file lands inrejected/with the correct diagnostic. -
Introduce one synthetic orphan (new
.agdanot imported fromAll.agda): observeorphan-modulehard-block.