dumbtv
dumbtv takes the ads, screen tracking and update nags out of your Fire TV over ADB. No root, none of your apps touched, every step can be undone. Free and open source.
翻譯準備中
獨立的安全驗證,針對人類與 AI 代理撰寫的程式碼。掃描、修復,然後證明——Dvalin 執行您專案的自訂檢查,並發佈可離線重新推導的驗證修復記錄。本地優先、政策綁定、MIT 授權。
AI 翻譯
Independent security verification for code written by humans and AI agents. Scan, repair, then prove it — Dvalin runs your project's own checks and issues a Verified Fix Record anyone can re-derive offline. Local-first, policy-bound, MIT.
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
Open security engineering for code written by humans and AI agents.
Every repair carries its own proof.
When an agent fixes a security finding, someone has to decide whether the fix
worked. Almost every tool asks the model that wrote it — which is the one
question a model cannot answer against its own interest.檢視完整 README ↗When an agent fixes a security finding, someone has to decide whether the fix worked. Almost every tool asks the model that wrote it — which is the one question a model cannot answer against its own interest.
Dvalin decides instead, and hands you the proof. It re-scans, runs your project's own tests itself, and reads the exit codes from processes it started. Who wrote the repair — our agent, Claude Code, Codex, Copilot, a person — is recorded and never consulted. The result is a Verified Fix Record: a small JSON file anyone can re-check offline, on a laptop with no network and no Dvalin state.
dvalin verify-fix fix-record.json
Fix record 2c9d71ac03e0 · VERIFIED · scan-and-checks
executor: claude-code (recorded, not consulted)
targets: 1 before · 0 remaining
coverage: complete → complete
introduced: 0 (gate high/new)
outcome: verified
✓ test: npm run test (exit 0)
audit: run verify-36509f42 @ 414644c75af0
That record says something narrow on purpose: these findings were gone, and these checks were observed to pass. It is not a claim that your code is safe, and Dvalin will not let it be read as one — every record carries what the scan actually covered, and a repair no check could confirm does not pass. The open profile →
A repair is a change, and a change can add as well as remove. So the record also
carries what the re-scan saw that the first scan did not, and the gate threshold
the verdict was reached under: a fix that removes an eval and introduces an SQL
injection is recorded as regressed and does not verify. Neither does a record
whose issuer never looked — introduced: not determined fails, because a
verifier that skips the question must not score better than one that asks it and
finds something.
Dvalin is the independent security runtime between code generation and merge. Humans, coding agents, and CI call the same versioned contract for discovery, remediation, and verification. It runs independently, or interoperates with specialist systems such as Codex Security through portable SARIF. Its built-in coding capability is a remediation executor — not the trust boundary, and not an attempt to compete with every general-purpose coding agent. See the security-agent strategy.
npx dvalincode security scan .
# After installing the package: dvalin scan .
That is the whole thing. It runs the built-in rules for injection, hardcoded
secrets, XSS, eval, and unsafe shell use against the current directory and
prints what it found. No account, no model, no config, no code leaves your
machine. The default policy runs only Dvalin Built-in, so the first scan always
works. Add optional engines explicitly, or inspect their fixed install commands:
dvalin scanners list
dvalin scanners install semgrep # review the command
dvalin scanners install semgrep --yes # execute it under Dvalin policy
dvalin init
init writes dvalin.security.json (fail on new findings at high or above),
names the checks your project actually has (test, typecheck, build,
lint) as what Dvalin runs before it calls a fix verified, records today's
findings as the accepted backlog in .dvalin/baseline.json, and writes a CI
gate for GitHub (.github/workflows/dvalin.yml) or GitLab
(.gitlab/dvalin-security.yml, with a Code Quality report for the merge
request widget). It never overwrites a file that is already there unless you
pass --force. Commit what it wrote, and the backlog stops blocking anyone:
only what a change adds fails.
To gate every commit locally too, add the pre-commit hook:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/arthurpanhku/dvalincode
rev: v0.22.0 # the hook ships in v0.22.0
hooks:
- id: dvalin-scan # or dvalin-scan-installed, to use the CLI you installed
If Snyk is what blocks your merges, verify against Snyk. A fix judged "clean" by a different engine is a fix the gate can still reject, and that mismatch is what turns one agent repair into several rounds of push, fail, and rebase.
npm install -g snyk && snyk auth # or set SNYK_TOKEN
dvalin scan . --scanners builtin,snyk-code,snyk-oss
snyk-code (SAST) and snyk-oss (dependencies) are engines like any other:
their findings carry the same fingerprints, coverage and gate, and a failed
login is reported as an engine error, which makes the scan partial, never
clean. They run only when named, because Snyk Code uploads source to Snyk.
Name them in dvalin.security.json to make them part of the policy, and
reverify will judge every fix with them.
If GitHub code scanning is the gate, use CodeQL the same way:
dvalin scan . --scanners builtin,codeql
codeql builds one database per language outside the workspace and runs that
language's default code-scanning queries, so its findings are the ones the gate
reports. JavaScript/TypeScript, Python, Ruby, Java and C# are analysed without a
build; Go uses CodeQL's autobuild. Kotlin, C/C++ and Swift need the project's own
build, so when they are in the tree the run says so and the scan is partial,
not clean. It runs only when named — a database takes minutes, not seconds, and
the CodeQL CLI's license covers open-source code and GitHub Advanced Security
customers.
Ignores Snyk itself reports as accepted are honored and listed as coverage
exclusions. Ignores the change under review adds are not: when a fix is
judged, .snyk, .semgrepignore, .trivyignore and .dvalincodeignore are
restored to the base commit's version and new inline markers (deepcode ignore, nosemgrep, nosec, NOSONAR, …) are blanked, so a finding that was
silenced rather than fixed still fails the fix. A suppression is a risk
decision a person makes in its own change, never a repair.
The same judgement applies wherever Dvalin says "verified": the fix loop,
dvalin verify, the MCP dvalin_verify_findings tool, single-round
--fix --verify, and CI reverify. Those records are dvalin-fix-record/v3,
which also fails a repair that hid a finding instead of fixing it — a sibling
sink, a deleted vulnerable file, deleted tests or assertions. Outside a git
repository, where the change cannot be determined, records stay v2 and say
that evasion was not evaluated.
dvalincode dvalin . --scanners builtin,snyk-code,snyk-oss --until-clean --max-rounds 3 --executor codex
--until-clean turns one fix attempt into a bounded loop. The executor edits;
Dvalin re-scans with the same engines and runs the project's checks itself;
the executor is sent only what is still wrong — targets still present,
findings its change introduced, failing checks with their last lines of
output, suppressions it added — and fixes again. Dependency findings go first.
The loop stops, and says which, when every target is gone with nothing
blocking introduced and every check passing (verified), when the round
budget runs out, when a round leaves the same problems open or the open set
stops shrinking (stalled), when the targets need a person — a dependency
with no fixed version (not-auto-fixable) — or when the engines or checks
cannot run (unverifiable). Suppressions the executor adds are undone before
each scan and stay open problems until removed. Every outcome issues a fix
record, and every round is logged under ~/.dvalincode/security/fix-loops/;
dvalin loop-stats summarizes those logs — how often loops reach verified,
the median and p90 rounds to green, which stop rule fired, and what was still
open when a loop stalled (--json, --since, --executor to slice it).
Rounds are kept short without changing what decides them. The engines run side
by side, so a scan costs the slowest engine rather than the sum. Between rounds,
the engines that analyse one file at a time (Dvalin Built-in, Semgrep) rescan
only the files the change touched and the files the targets are in; the others
always scan the whole tree. That narrowed scan only steers the executor: any
round that would stop the loop is re-judged on a full scan of the same tree, and
only the full scan decides the outcome and goes into the record.
--full-rescan scans everything every round, and loop-stats reports scan time
per round and how often a full scan changed the decision.
For code findings the loop first asks for a reproduction: tests only, which
Dvalin runs on the unfixed code and requires to fail — by a failing assertion,
not a missing runner or a not-yet-written import. The tests are hashed; the
fix must then make them pass unchanged, and that run is a check in the
record. A finding no test could demonstrate stops the loop as
not-reproduced before anything is fixed: it may be a false positive, and a
person triages it. The runner is inferred (vitest, jest, mocha, node --test,
pytest, go test) or set with --repro-command 'npx vitest run {files}' or
reproduce in dvalin.security.json — never chosen by the executor.
Each fix round also rejects the evasions an agent reaches for when the goal is
"the scanner went quiet": moving the sink to a sibling (eval →
new Function, exec → spawn with shell: true), deleting the vulnerable
file, deleting tests, removing assertions. In practice the scanner alone is
fooled by the first one — the rule stops matching — and the reproduction test
and the evasion check are what catch it.
dvalincode dvalin . --scanners builtin,snyk-code,snyk-oss --until-clean \
--rebase-onto origin/main --executor codex --draft-pr --sign-key ci.key
With --rebase-onto the loop fetches and rebases the fix onto upstream before
it starts and after every round, then judges it there. Conflicts go to the
executor — the conflicted files only, with "do not run git" — and Dvalin
continues the rebase itself; markers left in a file are a conflict not
resolved. If they cannot be resolved the rebase is aborted, the tree is left as
it was, and the loop stops as rebase-conflict. After each rebase the baseline
is re-scanned on the new base, so a finding a teammate landed on main is not
blamed on the fix.
--draft-pr commits the record at .dvalin/fix-record.json, and
docs/examples/dvalin-fix-loop.yml
re-executes it on the pull request with reverify: true: base and head
re-scanned, checks re-run, and the reproduction re-run with the fix reverted in
place (it must fail) and restored (it must pass) — then signed with the CI key.
For an incremental “no new high-risk findings” gate, commit the policy and baseline with the repository:
dvalin init
dvalin baseline
dvalin scan
This creates dvalin.security.json and .dvalin/baseline.json. Suppressions
require a reason and may have an owner and expiry date. Scan output is a
versioned envelope with a deterministic gate result and a resumable workflow ID.
# .github/workflows/security.yml
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0 # so the scan can reach the base commit
- uses: arthurpanhku/[email protected]
with:
fail-on: high
diff: true # only report on what this PR changed
Findings land inline on the pull request diff and in your Security tab. No API key, no secrets, no model — the scan is deterministic and local to the runner. Full example →
diff: true reports only on lines the pull request changed, so the gate blocks
what this change adds instead of everything the repository already carried.
That is what makes the check adoptable on a codebase that was not clean to
begin with. Drop it to scan the whole repository.
Every comment states what the scan covered — complete, partial, or
unknown — beside the result, because "no findings" from a run where half the
engines were missing is not the same answer as "no findings" from a complete one.
If your pipeline produced a fix record, hand it to the same action:
- uses: arthurpanhku/[email protected]
with:
fix-record: fix-record.json
The runner re-derives the record from the file alone — recomputing its hash and re-deriving its verdict from its own evidence — and posts the result on the pull request. A record that was edited after it was issued fails here, and fails the job.
Re-derivation proves the record is self-consistent. It cannot prove the record was issued by anyone who actually ran anything: every field in it, the exit codes included, is something a forger could write, and a self-consistent forgery re-derives. Two things close that gap — re-execute the claim on the runner, and sign what the runner observed.
🔏 Verified Fix Record
✅ ce504a995395 · VERIFIED · scan-and-checks
- repaired by claude-code — recorded, and not consulted for this verdict
- targets: 1 before → 0 remaining
- coverage: complete → complete
- introduced: none (gate high/new)
- outcome: verified
- ✓ test: `npm run test` (exit 0)
- audit chain: verify-eeb1bae7 @ 80881867270d
A repair that regressed says so in the same place, and fails the job with it:
❌ 916e2eeaf065 · NOT VERIFIED · scan-and-checks
- introduced: 1 finding(s) the first scan did not report (gate high/new)
- critical dvalin/sql-injection — src/db.ts:31
- outcome: regressed
- uses: actions/checkout@v5
with:
fetch-depth: 0 # the base commit has to be reachable
- run: npm ci # the project's checks run on the runner
- uses: arthurpanhku/[email protected] # reverify ships in v0.22.0; until it is tagged, pin a main commit SHA
with:
fix-record: fix-record.json
reverify: true
signing-key: ${{ secrets.DVALIN_SIGNING_KEY }} # optional
With reverify: true the claimed record contributes only which targets it
says it fixed and who the executor was. Everything else is observed again:
dvalin.security.json — a pull
request that relaxes its own gate or deletes its own checks is judged under
the rules it is trying to change;With signing-key the fresh record is signed (Ed25519, over its hash). The key
is taken into memory and removed from the environment before the project's
checks run, so the code under review cannot read it. Downstream — a release
job, another repository, an auditor — can then require that signature:
dvalin keygen --out ci # once; store ci.key as a secret, publish ci.pub
dvalin verify-fix record.json --trusted-key ci.pub
A record that is unsigned, or signed only by a key you did not name, fails
under --trusted-key. A valid signature says which key vouched for this
record; whether that key deserves trust is your decision, and the reason to
trust a CI key is that the CI job re-executed the verification rather than
copying it. Locally, dvalin reverify <record> --base origin/main runs the same
re-execution, and dvalin sign-fix signs a record that re-derives.
FVP-1 §4a, §5a →
If an agent is writing the code, something other than that agent has to check it. DvalinCode is an MCP server, so any agent that speaks MCP can:
claude mcp add dvalin -- npx -y dvalincode mcp-serve --workspace .
One command configures the editor you actually use:
npx dvalincode mcp-install cursor # .cursor/mcp.json
npx dvalincode mcp-install vscode # .vscode/mcp.json
npx dvalincode mcp-install claude-code # .mcp.json
The formats differ in a way that fails silently — VS Code keys its servers under
servers, Cursor under mcpServers — so the command writes the right one and
merges into whatever is already there. Editors and MCP →
dvalin_scan accepts diff: "uncommitted", which reports only on what the
agent just wrote rather than everything the repository already carried — the
difference between a usable answer and a wall of pre-existing findings. It never
runs a model, edits the target workspace, or persists Dvalin state, so clients
can allow the preview by default. When a finding will be repaired, the agent
explicitly calls dvalin_begin_verification to record a small local workflow;
it can then retrieve the finding by fingerprint and request an independent
re-scan through dvalin_get_finding and dvalin_verify_findings.
That last one is the point: an agent that has just written a repair can ask for
an independent verdict on it. Dvalin re-scans, runs the project's own checks
itself, and returns a Verified Fix Record — what was targeted, what remains,
what the repair introduced that was not there before, the gate the verdict was
reached under, which commands ran and the exit codes Dvalin observed, and how
much of the codebase was actually covered. Whoever wrote the repair is recorded
and never consulted. dvalin_verify_fix re-derives such a record offline, so the reviewer
receiving it does not have to trust the tool that issued it.
FVP-1 → Responses include MCP structuredContent; scanner
readiness is available through dvalin_list_scanners. The same server exposes
dvalin_run_task as an optional implementation helper, plus session and audit
evidence tools.
Every client below has been driven to a real tool call rather than only a handshake — which client, which version, and on what date is a table rather than a sentence, because hand-written version numbers go stale quietly. Integration support ↓ · Agent integrations →
The repository also contains one dual Codex/Claude plugin payload with both native manifests, the shared security-gate skill, and the local MCP server configuration. Installing it makes the gate discoverable from task context instead of requiring every developer to remember a scan prompt. Codex honors the scan's read-only MCP annotation. Claude Code requires one explicit MCP permission by design; the plugin documents the exact scan-only allow rule instead of asking users to bypass all permissions.
One server, reached the way each tool expects:
| Harness | How Dvalin reaches it |
|---|---|
| Claude Code | dual plugin or claude mcp add · standalone skill |
| Codex | dual plugin or codex mcp add · SARIF interop with Codex Security |
| Cursor | dvalincode mcp-install cursor |
| VS Code | dvalincode mcp-install vscode · extension for Problems, coverage/gate status, and offline VFR verification — built, not yet published |
| Windsurf · Zed | stdio MCP through their own settings — server command |
| Any MCP client | MCP registry: io.github.arthurpanhku/dvalincode |
| GitHub Actions | Marketplace action — findings inline on the pull request diff |
| GitLab CI | dvalin init --ci gitlab — new findings gate the merge request, shown in its Code Quality widget |
| pre-commit | hook — the same policy gate before every commit |
The MCP config formats are not interchangeable — VS Code keys its servers under
servers, Cursor under mcpServers, and the wrong one fails silently — so
mcp-install writes the right shape and merges into whatever is already there.
Editors and MCP →
Codex Security can export a completed, sealed scan as SARIF. Import that portable projection without coupling Dvalin to Codex Security's private state directory:
DVALIN_CODEX_SCAN_DIR=/tmp/codex-security-results
npx @openai/codex-security scan . --output-dir "$DVALIN_CODEX_SCAN_DIR"
npx @openai/codex-security export "$DVALIN_CODEX_SCAN_DIR" \
--export-format sarif --source-root "$PWD" --output /tmp/codex-security.sarif
dvalin import /tmp/codex-security.sarif .
dvalin scan . --fail-on high
The import creates stable Dvalin remediation cases; --no-persist validates the
handoff without changing the backlog. Keep Codex Security's original manifest,
findings, and coverage artifacts together—Dvalin imports the SARIF finding
projection but does not rewrite its sealed bundle or reinterpret its coverage.
Integration guide →
dvalincode dvalin . --fix --verify --draft-pr
This step does use a model — your model, any OpenAI-compatible endpoint. It prepares focused repairs in an isolated worktree, runs your tests, and requires a clean re-scan before anything can proceed to a draft PR. It never auto-merges, and a clean scan is never treated as proof that the code is safe.
This animation is made from the real application, not a mock. The input is an Apache-2.0-licensed example adapted from OWASP NodeGoat, whose contribution route evaluated user-controlled text.
Dvalin turns open-source scanner evidence into a controlled scan → fix → test → re-scan → draft-PR workflow. Here is the run in the animation above, measured:
| Real NodeGoat-derived run | Before | After Dvalin remediation |
|---|---|---|
| Security health (triage heuristic) | 22 / 100 · F | 100 / 100 · A |
| Findings | 10 (eval across 3 rules, 2 engines) | 0 |
| Tests | 2 passing | 3 passing, including an injection regression test |
| Scanner fleet | 4 / 4 completed | 4 / 4 completed |
The scanning and hardening control plane uses open-source components:
The scanners find and rank evidence. The configured model proposes source changes; DvalinCode constrains that work, records the diff, runs project tests, re-scans the changed tree, and keeps PR publication explicit. It does not auto-merge and it does not claim that a clean scan proves the absence of bugs. Choose an open-weight model through Ollama if the repair-proposal step must also stay fully local and open; hosted model licensing depends on the provider.
You can still prove what the agent did after the fact:
dvalincode report verify # re-derive the hash chain of the last run's audit log
Code written with an AI assistant passes through four sets of hands before it merges: the agent that writes it, the editor the developer reads it back in, the pull request that gates it, and the reviewer who has to believe the result. A security answer that exists in only one of those places is not a gate — it is a suggestion the next stage is free to ignore.
Dvalin is one MCP server and one deterministic scan behind all four, so the answer does not change depending on who asks it.
| Stage of the loop | Where you are | How Dvalin gets there | Status |
|---|---|---|---|
| Writing the code | Claude Code | dual plugin · claude mcp add · mcp-install claude-code | ✅ session verified |
| Codex | dual plugin · codex mcp add · SARIF interop | ✅ session verified · capture below | |
| Cursor | dvalincode mcp-install cursor | ⚙️ config verified | |
| Windsurf · Zed | stdio MCP through their own settings | ⚙️ documented, unverified | |
| Any MCP client | registry io.github.arthurpanhku/dvalincode | ⚙️ published | |
| Reading it back | VS Code | mcp-install vscode · extension for Problems, coverage and gate status | ✅ editor verified |
| Gating the merge | GitHub Actions | Marketplace action — findings on the diff, fix records re-derived on the runner | ✅ runs on this repository's own CI |
| Any CI | dvalin scan . --fail-on high, SARIF out for code scanning | ✅ the exit code is the contract | |
| Believing the result | anyone, offline | dvalin verify-fix record.json --trusted-key ci.pub | ✅ no workspace, no network, no Dvalin state |
| the merge gate | reverify: true — base and head re-scanned, checks re-run on the runner, fresh record signed |
✅ means a real client was driven end to end and the tool call was observed. ⚙️ means the configuration is generated and its shape is tested, but no session has been captured. The difference is not smoothed over here, because a config file that loads is not evidence that a tool was ever called.
| Client | Version | Checked | How |
|---|---|---|---|
| Claude Code | CLI 2.1.260 | 2026-09-04 | server connected, dvalin_scan called with only that tool allow-listed, three findings returned — capture below |
| Claude Code | CLI 2.1.251 | 2026-08-31 | weekly harness-interop — a real handshake against the built binary, which needs no credentials |
| Codex | CLI 0.153.2 | 2026-09-18 | real dvalin_scan call in an ephemeral read-only sandbox; the completed MCP event was recorded as JSONL and returned one dvalin/eval finding — capture below |
| Codex | CLI 0.151.0 | 2026-08-31 | weekly harness-interop — the server spec is accepted and stored as stdio. Not a handshake: the tool-call step stays skipped until CODEX_API_KEY is set |
| VS Code | 1.134.0 · extension 0.18.0 | 2026-09-03 | packaged VSIX in a clean profile; finding, gate and coverage rendered in the editor — capture below |
| Cursor | — | 2026-09-04 | mcp-install cursor writes .cursor/mcp.json under mcpServers; no session has been captured |
That weekly workflow exists because an earlier version of this claim named two CLI versions by hand, both went stale within weeks, and nothing said so. It now re-checks against whatever those tools shipped that week, so the dates above either move on their own or stop moving in public.
Claude Code — one read-only tool allow-listed, and the MCP call itself:
Codex — one read-only MCP call, with the completed JSONL tool event shown separately:
VS Code — the same scanner contract, as squiggles and a status bar:
That last command is the part that matters once more than one person depends on this. DvalinCode is a full coding agent — terminal, web GUI, and desktop app — built so that an organization, not the developer, bounds what it may do: a policy file constrains modes, commands, paths, tools, and models; every run is hash-chained into a tamper-evident audit log; nothing reaches a provider that the egress guard did not allow. A repo policy can only ever narrow the machine-level one.
If you are the person who has to approve this class of tool, start at APPROVABILITY-PLAN.md and the Evidence Pack that every release ships of itself.
Make every code-producing human or agent pass the same independent security gate.
DvalinCode is built as an agent-compatible security runtime, not another general coding-agent benchmark entry. The core product is scan evidence, policy, baseline, deterministic verification, and portable interfaces that a human developer, an external agent, or CI can all call. The bundled coding agent stays capable enough to implement and test focused remediations reliably; its model prose never decides whether the security gate passed.
dvalincode trust makes the posture self-verifiable (transparent), and the hash-chained log proves what every run did (auditable). Those three together are exactly what a security review needs to say yes — and what cloud, closed, mutable-log agents structurally struggle to provide. Approvability plan →The bundled web GUI is the runtime's reference implementation and showcase — the first consumer of that public API, demonstrating everything the runtime can do.
DvalinCode is differentiated by approvability. It is built for teams that need AI coding to pass security, compliance, and data-governance review before it can touch production repositories.
dvalin/remediate/... worktree; then send a focused repair prompt with
source context and verification instructions.~/.dvalincode/; .dvalincodeignore and policy controls
bound what the agent can read, write, or execute.DvalinCode maintains project-level governance evidence for open-source and enterprise review. This is the differentiator for teams where AI coding must pass security approval before it can reach production repositories:
AGENTS.md, poisoned MCP servers, prompt-injection escalation,
egress, audit tampering, supply chain, sandbox escape), each mapped to the
control that defends it and the honest residual gap. Threat model →These documents are implementation evidence and operating procedures; they do not claim third-party ISO certification.
continue
resumes from the actual workspace progress.git and GitHub CLI
(gh) operations now support pull, push, PR creation, and Actions/repository
commands through the governed shell approval path.prepublishOnly runs the build, typecheck, and test suite before publishing.DvalinCode.app
opens a real dock window (WKWebView, no Electron) over the embedded engine.
Two threading bugs that shipped in every earlier desktop build are fixed:
the blocking webview loop no longer starves the embedded server (blank
window), and the webview runs on the main thread as macOS requires (no
window at all) — the server now lives in a child process of the same binary.curl … install.sh | bash now also puts DvalinCode.app (with the
DvalinCode icon) into /Applications, so the desktop window launches
straight from Launchpad after a CLI install. Opt out with
DVALINCODE_NO_APP=1; pin with DVALINCODE_GUI_VERSION.dvalin.policy.json lets a company, not the developer, bound the agent: which modes, shell commands, file paths, tools, and models are allowed. Two layers (machine ~/.dvalincode/policy.json + repo) resolve by narrowing — a repo policy can only ever make the machine policy stricter, never widen it. With no policy file, behavior is identical to before. Enforced at a single chokepoint; every denial is an inline ⛔ Blocked by policy plus a policy_violation audit event. Policy reference →dvalincode trust — prints this install's live security posture in one command — active policy + source hashes, audit status, runtime, dependencies — so a reviewer can verify what the agent may and may not do directly, instead of taking claims on trust. --json for tooling.dvalincode policy check — validates dvalin.policy.json against the schema, prints the resolved policy + canonical hash (after narrowing with the machine layer), and exits non-zero on failure — for CI and policy authoring. Policy reference →run_start, so the tamper-evident log proves which rules were in force.dvalincode export / dvalincode import, or the Export / Import buttons in the GUI Settings panel.dvalincode session md <id>, or GET /api/sessions/:id/markdown.DvalinCode.app on macOS, plus Windows/Linux builds. Built with webview-bun using the OS-native webview (WKWebView / WebView2 / WebKitGTK) — no Electron, stays a small self-contained binary.dvalincode binary is now positioned purely as the CLI (terminal + serve).dvalincode bare for an interactive terminal coding agent, Claude-Code-style: streaming responses, inline [y/N] write approvals with red/green diffs, /mode · /clear · /git · /plan · /compact · /undo · /help, Ctrl-C to interrupt, and a guided first-run provider setup. Defaults to read-only Chat, switchable live.dvalincode serve — the web GUI now lives behind a command, so the same binary deploys headless on a server: dvalincode serve --host 0.0.0.0 --no-open.src/agent/session.ts), keeping them at feature parity.~/.dvalincode/audit/ (run_start, every tool_call / file_* / shell_exec / approval, run_end). The hash chain makes any after-the-fact edit detectable. No local coding agent ships verifiable behavior logs. Format + threat model →dvalincode report CLI — a Markdown summary of each run (files read/changed, commands, decisions, test result), rendered as a collapsible card in the GUI and from the CLI:
dvalincode report --last # render the most recent run
dvalincode report <run-id> --format json
dvalincode report verify <run-id> # ✓ chain intact / ✗ broken at seq N
system follows your OS live; the choice persists across sessions./compact — LLM-based context compaction: replaces conversation history with a structured five-section summary (Goal / Completed / Decisions / Current State / Pending). A divider in the chat thread shows the token reduction (e.g. 8,412 → 1,203 tokens −85%).dvalin.json team playbook — commit a shared set of automation prompts to your repo. The sidebar loads them automatically and lets teammates run the same one-click routines without any manual setup. Export button converts your personal routines to dvalin.json in one click.bun --compile so the web UI is bundled alongside the server binary.localStorage.curl … | bash auto-detects your OS + arch, drops the binary into ~/.dvalincode/, and patches your PATH. No package manager dependencies.A real Dvalin scan of vulnerable code — Security health 22/100 · F, with the 10 findings the engines actually reported, located to the line:
The verified result — a real model-driven Verify turn inspected the repair, ran the regression tests and all four open-source engines, then the deterministic server re-scan reported complete coverage, a passing gate, 0 findings, 100/100 · A:
On 2026-09-18, commit d4bf02b was built and run as the local app on an
Apple-silicon Mac mini with macOS 27.0. The disposable test project had no API
key or configured model, and selected only the network-independent built-in
scanner. Dvalin located a deliberately vulnerable eval at quantity.js:3,
reported 1 high finding, 88/100 · B, recorded complete 1/1 selected-engine
coverage, and blocked the high security gate:
After replacing eval with a constrained integer parser and adding an
executable-input regression test, all 3/3 tests passed. The selected engine
then reported 0 findings, 100/100 · A, complete coverage, and a passing gate:
The same CLI workflow ran npm run test with exit code 0, issued a
dvalin-fix-record/v2, and dvalin verify-fix re-derived it offline with
ok: true. The clean-scan screenshot was captured before that record was
imported, so it still says Offline fix record: Not attached. The Web workspace
can now import the portable JSON record, re-derive its hash and verdict offline,
and display its executor, checks, and exit codes. A clean scan is evidence about
the selected engine, not a claim that the code is proven safe.
Home → Code → Dvalin — the current workspaces:
The scan images above are unedited captures of a real run against the documented NodeGoat-derived case: the scanners were run, the model repaired the source, the project's tests were run, and the tree was re-scanned. Nothing is staged, and a 100/A means the configured engines found nothing — not that the code is proven safe.
| If you need… | DvalinCode's answer |
|---|---|
| An agent your security team can approve | Policy-bound tools, explicit approval modes, dvalincode trust, audit logs, OpenSSF evidence, and ISO/IEC 42001 alignment docs. |
| AI coding for regulated repositories — finance, healthcare, enterprise data, customer-confidential code | Local-first runtime, bring-your-own-model, .dvalincodeignore, governed egress, and minimized audit records. |
| A safer alternative to generic autonomous coding agents | The product thesis is controllable / transparent / auditable, not only "the model can edit files". |
| IDE-centric AI workflows | Zero-dep binary (~25 MB). Runs anywhere, no IDE required. macOS shell is sandboxed by default — network denied, writes capped to cwd. |
| Terminal-first AI workflows | CLI start → auto-opens a modern Web UI with code highlighting and red/green diff approval. One install command, nothing else needed. |
| Cloud-only AI workflows | Every OpenAI-compatible endpoint is a first-class citizen. Run Ollama with Qwen2.5-Coder: no key, no internet, no per-token cost. |
| Single-machine AI setup | AGENTS.md committed to the repo ships AI context to every clone. dvalin.json ships the team's automation commands the same way — export from the sidebar, commit, done. |
brew tap arthurpanhku/dvalincode https://github.com/arthurpanhku/dvalincode
brew install arthurpanhku/dvalincode/dvalincode
Installs the same signed-by-checksum release archive the one-liner does, and
brew upgrade keeps it current. Homebrew never applies the macOS quarantine
attribute, so this path is not subject to Gatekeeper.
curl -fsSL https://raw.githubusercontent.com/arthurpanhku/dvalincode/main/scripts/install.sh | bash
Detects your OS + arch, downloads the right binary, installs to ~/.dvalincode/, and adds it to your PATH. On macOS it also installs the native DvalinCode.app into /Applications (skip with DVALINCODE_NO_APP=1), so the desktop window launches straight from Launchpad. After reload:
source ~/.zshrc # or ~/.bashrc
dvalincode # interactive terminal agent
dvalincode dvalin . # white-box security scan (GUI-independent)
dvalincode serve # start the web GUI, open the browser
dvalincode serve --host 0.0.0.0 --no-open # host it on a server for remote/browser use
echo "inspect src and summarize" | dvalincode run - --output-format stream-json
dvalincode mcp-serve # task-level stdio MCP server for external agents
Headless run and mcp-serve keep the same policy and audit chokepoint as
the interactive clients. See the unattended recipes
for cron, CI, and external-agent examples.
A run that scanned or filed a fix record also carries a verification envelope
beside its answer — in json, in stream-json, and in the MCP dvalin_run_task
result. coverageStatus is the weakest coverage the run has evidence of, so
one complete scan cannot speak for a partial one, and any record it produced is
listed by path for offline re-derivation. A CI gate can read it directly:
jq -e '.verification.coverageStatus == "complete"' run.json || exit 1
That is the same rule the pull-request comment applies, on the surface with no human watching. Harness mode →
Download dvalincode-v*-windows-x64.zip from Releases, unzip, then double-click start.bat.
Grab the archive for your platform from the Releases page:
| Platform | Archive |
|---|---|
| macOS Apple Silicon (M1/M2/M3) | dvalincode-v*-macos-arm64.tar.gz |
| macOS Intel | dvalincode-v*-macos-x64.tar.gz |
| Windows x64 | dvalincode-v*-windows-x64.zip |
| Linux ARM64 | dvalincode-v*-linux-arm64.tar.gz |
| Linux x64 | dvalincode-v*-linux-x64.tar.gz |
Verify against SHA256SUMS.txt (included in each release).
Each release also ships dvalincode-v*-evidence.json — an Evidence Pack the
shipped binary produced of itself on the build machine: two real governed runs,
one allowed and one blocked by policy, with their hash chains. You can check the
claims on this page before installing anything:
dvalincode evidence verify dvalincode-v0.14.0-evidence.json # offline, reads only the file
The pack's checksum is inside SHA256SUMS.txt, which is the subject of the
release's build-provenance attestation. How it is produced →
macOS Gatekeeper: binaries are unsigned. On first run, either clear the quarantine flag with
xattr -dr com.apple.quarantine ~/.dvalincode, or right-click the binary in Finder → Open → confirm.
DvalinCode updates itself — no need to re-run the installer:
dvalincode update --check # is a newer release out? (read-only)
dvalincode update # download, verify, and install the latest
It finds the newest release on GitHub, and for a binary install downloads the
matching archive, verifies it against the release's SHA256SUMS.txt before
swapping anything in, then replaces ~/.dvalincode/ in place. npm installs are
updated via npm i -g, and source checkouts are pointed at git pull. Add
-y to skip the prompt, --prerelease to track pre-releases, or --json for
scripting.
The macOS desktop app checks the separate gui-v* release track when it starts.
When a newer GUI is available, it asks before downloading, verifies the archive
against SHA256SUMS-gui.txt, validates the app version, then replaces and
restarts DvalinCode.app. A failed replacement rolls back to the previous app.
Terminal (default): run dvalincode. On first launch it walks you through a one-time provider setup (pick a provider, paste your API key, choose a model) and saves it to ~/.dvalincode/config.json. Then you're at the prompt — type to chat, /mode to switch between Chat / Cowork / Code / Dvalin, /help for commands. In the GUI, Chat and Cowork are grouped under Home.
Web GUI: run dvalincode serve and:
http://localhost:3000 and your browser opens automatically.fast, cheap, local-ollama) to switch quickly later.Both share the same config and sessions in ~/.dvalincode/.
| Category | Feature | Notes |
|---|---|---|
| Modes | Home / Code / Dvalin | Home contains read-only Ask and approval-gated Collaborate; Code is focused autonomous development; Dvalin is the scan-to-fix security workspace |
| Code permissions | Ask Permissions / Plan Mode / Auto Mode / Bypass permissions | Verified behavior: Ask requests approval before writes/commands, Plan is read-only and does not write files, Auto runs operations automatically, Bypass runs without confirmation prompts |
| Workspaces | Open folder / Import Git / Add worktree | Cowork and Code can switch to a local folder, clone a Git project, or create a Git worktree from the UI |
| Governance | OpenSSF Scorecard / ISO 42001 AIMS alignment | Scorecard, CodeQL, Dependabot, pinned Actions, AI impact assessment, risk register, and review cadence are documented under docs/security/ and docs/governance/ |
| Secure remediation | Built-in + Semgrep CE + Trivy + OSV-Scanner / SARIF / cases / worktrees / tests / draft PR | Dvalin detects installed engines, normalizes SARIF, scores risk, persists cases, drives evidence-backed fixes, verifies changes, and publishes only after an explicit user action |
| Skills | Upload / download / built-in security skills | Skills live under ~/.dvalincode/skills; built-ins guide security scanning and remediation with dedicated agent tools. Format → |
| Composer | @ file references | Type @ for a fuzzy file search; selected files get inlined into the prompt |
/ slash commands | /clear /compact /git /plan /undo /help | |
| Multiline + interrupt | Shift+Enter for newline, stop button to abort mid-stream | |
| Tool UI | Inline diffs | edit_file and write_file results render as red/green unified diff, default folded |
| Command | Description |
|---|---|
/clear | Clear the current conversation (client-side, starts a fresh session) |
/compact | LLM-based context compaction — replaces history with a structured summary |
/undo [N] | Reverse the last N tool calls (default 1) |
/git | Run git_status and show branch, recent commits, changed files |
/plan <task> | Ask the agent to plan the task step-by-step without executing |
/help | Show all available slash commands |
┌───────────────────────────┐ ┌─────────────────────────┐
│ Terminal UI (readline) │ │ Browser GUI (React/Vite)│
│ streaming · approvals │ │ ChatThread · DiffViewer │
└─────────────┬─────────────┘ └────────────┬────────────┘
│ in-process HTTP / WebSocket
│ ┌───────────────▼─────────────┐
│ │ Express + ws server │
│ │ /api/* · `dvalincode serve` │
│ └───────────────┬─────────────┘
└──────────────┬─────────────────┘
┌────────────────────────────▼────────────────────────────┐
│ runAgentTurn — shared turn-runner (src/agent/session) │
│ provider · prompt (mode · git · AGENTS.md) · session │
└────────────────────────────┬────────────────────────────┘
│
┌────────────────────────────▼────────────────────────────┐
│ Agent Engine │
│ AgentLoop (8-state machine) → AgentRunner │
│ Streaming · Interrupt · Undo stack · LLM compaction │
│ run_start / run_end → AuditSink (hash-chained JSONL) │
└──────────────────────────┬──────────────────────────────┘
│ run()
┌──────────────────────────▼──────────────────────────────┐
│ ToolRegistry — Zod schemas + permission gating │
│ + audit taps: tool_call · file_* · shell_exec │
│ read_file · list_files · search_text · git_status · │
│ write_file · edit_file · delete_file · shell │
└─────────────────────────────────────────────────────────┘
RESTORE → COMPACT → COMMAND → BUILD → RUN → SAVE → RESPOND → DONE
~/.dvalincode/sessions/AgentRunner for the LLM tool-calling loopnpm test
584 core tests · 74 files · all green. The VS Code extension has a separate 37-test suite plus one opt-in published-package integration test.
Requires Bun (curl -fsSL https://bun.sh/install | bash).
git clone https://github.com/arthurpanhku/dvalincode
cd dvalincode
npm install
npm run dev:all # start backend (3001) + Vite (5173)
Build release binaries for every platform:
bash scripts/build-release.sh # → release/ with tar.gz / zip + SHA256SUMS.txt
bash scripts/build-release.sh darwin # macOS only
bash scripts/build-release.sh windows # Windows only
Before publishing a release:
(cd release && shasum -a 256 -c SHA256SUMS.txt)
unzip -l release/dvalincode-v*-windows-x64.zip | grep 'web/dist/index.html'
tar tzf release/dvalincode-v*-macos-arm64.tar.gz | grep 'DvalinCode.app/Contents/Resources/AppIcon.icns'
Windows smoke test: unzip dvalincode-v*-windows-x64.zip on Windows and run start.bat from the extracted folder. The server should open http://localhost:3000. If it reports an ENOENT path under B:\~BUN\root\web\dist, the compiled Bun virtual path detection has regressed; the packaged binary must resolve web/dist beside the extracted executable.
Note: Bun only allows Windows .exe icon/metadata injection when compiling on Windows. macOS/Linux cross-builds still produce a valid Windows archive, but without an embedded .exe icon.
DvalinCode supports any OpenAI-compatible endpoint. Built-in presets, sorted by cost:
| Provider | Cheapest model | Input / Output | Notes |
|---|---|---|---|
| Groq | llama-3.1-8b-instant | Free tier | Fastest open models — Llama 3.3 70B, Mixtral |
| Ollama | qwen2.5-coder | $0 (local) | No API key needed, runs on your machine |
| DeepSeek | deepseek-chat | $0.14 / $0.28 per 1M | Cheap and strong; v3 nearly matches GPT-4 quality |
| OpenRouter | google/gemini-2.0-flash-001 | $0.10 / $0.40 per 1M | 200+ models including Claude, Gemini, Llama |
| OpenAI | gpt-4o-mini | $0.15 / $0.60 per 1M | Reliable; o1 available for deep reasoning |
| Custom | — | depends | Any OpenAI-compatible base URL |
DvalinCode shows the per-session cost live in the topbar — flip between providers in the LLM Configuration modal, save named profiles, and compare on the fly.
Contributions welcome. The codebase is intentionally small and surgical — see CONTRIBUTING.md.
git clone https://github.com/arthurpanhku/dvalincode
cd dvalincode && npm install
npm test # 584/584 core tests ✅
npm run typecheck
MIT — see LICENSE.
DvalinCode is an independent implementation. It is not affiliated with, sponsored by, or endorsed by Anthropic, Claude, Claude Code, OpenAI, OpenAI Codex, GitHub, Cursor, Aider, opencode, Cline, HKUDS/nanobot, or any other project or vendor named here.
We gratefully acknowledge that DvalinCode's product direction and architecture were informed by public research, open-source projects, published papers, standards, release notes, and common workflow patterns across the agentic coding ecosystem:
TurnState flow.tool_calls message format, along with the broader
OpenAI-compatible provider ecosystem, gives DvalinCode a portable interface
for model/tool interaction.AGENTS.md project-instruction convention, common in coding-agent tools,
informed DvalinCode's project-local instruction loading behavior.These references shaped our understanding of what users expect from coding agents. DvalinCode's source code, prompts, UI text, tool schemas, module layout, and product implementation remain original unless explicitly noted. No source code, prompts, or UI text from the projects above was copied.
Full source references: docs/REFERENCES.md
| Contributor | GitHub profile |
|---|---|
| Arthur Pan | @arthurpanhku |
| Shivas | @shivasb42 |
| Aditya | @adity982 |
| badhope | @weed33834 |
| Samran Asif | @webdevsamran |
| dchaudhari7177 | @dchaudhari7177 |
| TayfurYldz | @TayfurYldz |
See the complete contribution history, including automated dependency and maintenance updates.
dvalin-scan| Any CI | dvalin scan . --fail-on high, SARIF out for code scanning |
| ✅ covered by the test suite |
| Approval dialog with diff | Cowork mode shows the diff before the change is applied |
| Live tool counter + token + cost | Topbar shows session totals in real time |
| Agent | LLM-based context compaction | /compact summarises into Goal / Completed / Decisions / Pending |
| Persistent undo stack | /undo [N] reverses the last N tool calls |
| Run Report | Markdown summary per run (files, commands, decisions, test result) — GUI card + dvalincode report |
| Git awareness | Branch name in topbar; git_status tool; git context auto-injected into prompt |
AGENTS.md project memory | Per-repo persistent instructions, auto-loaded each turn |
| Security | Tamper-evident audit trail | Hash-chained JSONL per run in ~/.dvalincode/audit/; dvalincode report verify detects edits |
| macOS shell sandbox | sandbox-exec denies network; allows writes only inside cwd + /tmp |
.dvalincodeignore | gitignore-style exclusion; blocks read_file / list_files / search_text |
| Per-action approval | Approve/deny each write / delete / shell call in Cowork mode |
| Appearance | Theme switcher | Dark / light / system, persisted; system follows the OS live |
| Providers | OpenAI-compatible endpoints | DeepSeek · OpenAI · Groq · OpenRouter · Ollama · custom |
| Multi-profile config | Save and switch between named (provider, model, API key) sets |
| Sessions | Auto-save + restore | All sessions persisted to ~/.dvalincode/sessions/ as JSON |
| LLM summary memory | Cross-session summary keeps the agent oriented after restart |
| Memory | Local user/project memory | Searchable facts, preferences, and decisions in ~/.dvalincode/memory/; import from Claude/Hermes/Markdown |
| Data portability | Export / import all data | One bundle of memory + sessions + config + audit — dvalincode export / import, or GUI Settings → Export / Import |
| Markdown transcript | Download any conversation as Markdown — sidebar download icon, dvalincode session md <id>, or /api/sessions/:id/markdown |