Skip to content

Repository files navigation

CodeFlux — verified atoms, better software

CodeFlux

Verified atoms. Better software.

An experimental coding agent that assembles programs out of separately verified atoms instead of writing them in one pass.

Read the case study →

Main gate Dev pass CodeQL License: MIT Go 1.26+ Platforms Status: prototype

The idea · Quickstart · How a run produces code · What it will not do · User guide · Contributing


The idea

Most coding agents write a program in one pass and then try to check it. CodeFlux builds one from the bottom up, out of atoms.

An atom is a reusable unit with a stable identity, a typed signature, a contract, documentation, declared effects, and the evidence that it works. It is larger than a helper function and smaller than a workflow. An atom reads nothing outside its arguments, so what it does is determined by what you pass it.

Atoms compose into molecules, molecules into control flow, control flow into a program. Each layer states what it must guarantee, and each guarantee names the pieces that discharge it.

Correctness is the dimension being optimized. Everything else is downstream of it. Cost is the interesting consequence: a verified atom is project capital, so the next task that needs it recalls it instead of rebuilding it. A run carries 41 stages; reusing an atom excuses 11 of them — the ones that would have established it — and replaces all 11 with a single obligation: it must still pass the new run's tests, derived from the new contract. Reuse without that re-verification would just inherit the old blind spot, in every program that touched the atom, invisibly. The saving is one test run, not the whole atom.

That is also where the cost theory lives. If a program can be assembled from atoms that are already verified, assembly is a smaller job than authorship, and a cheaper model may be able to do it. Whether that holds is not settled.

This is a bet, and it is written down as one. Two of them, and they fail separately:

  1. Decomposition. Building from pure, separately verified units produces more correct programs than writing one in a pass and checking it afterwards.
  2. Reuse. A verified atom is project capital, so marginal cost falls as a project accumulates atoms.

The second depends on the first and not the reverse. Decomposition can be worth its cost even if nothing is ever reused; reuse is worthless if the units being reused were not worth trusting. Keeping them apart is what lets one be abandoned without the other.

Both carry an explicit kill criterion. If reuse produces no measurable improvement in defects, review time, or total cost once the registry holds enough compatible atoms to exercise, reuse goes and decomposition stays on its own merits. If decomposition also fails to beat a disciplined one-pass agent at equal correctness, the bet has lost and this README is wrong. The prototype exists to find out — see Project status for which half is currently evidence and which is still design.

Two habits hold the rest together. Authority comes from what an action is — the tool, its ordered arguments, its declared effects — not from what the model says it needs, so a poisoned file can persuade a model to propose something but cannot make it authorized. And what is known, what is ambiguous, and what is recommended stay three separate things: a forecast is a range, an unreported price stays unknown rather than becoming zero, and a passing check means those checks passed and nothing more.


Quickstart

CodeFlux is one executable. It installs per user and never needs administrator rights — a coding agent asking for elevation is asking for far more trust than it needs.

# 1. Verify the download against its published SHA256SUMS, then put it on PATH.

# 2. Check the install. Reports every prerequisite as ok / missing / degraded /
#    failed / unknown, with a next step for anything that is not ok.
codeflux doctor

# 3. Connect one provider. The credential is read from standard input — never
#    from an argument, which every process on the machine can see and which
#    your shell history keeps — and is stored in the OS credential store.
codeflux provider set --name anthropic

# 4. Start. Binds loopback, opens your browser, prints the URL.
codeflux start

The session secret is not printed. A secret echoed to a terminal survives in scrollback and in shell history; your browser receives it instead as an HttpOnly, same-site cookie you never type. Use --no-browser to print the URL and open it yourself.

Then, in the interface:

  1. Choose a repository. A local Git repository with a clean working tree. Uncommitted changes are accepted only after you see and acknowledge exactly what they are — otherwise there is no way to tell your edits from the agent's.
  2. Describe an outcome in your own words. No specification required.
  3. Read the plan. CodeFlux proposes scope, steps, the checks it intends to run, and the authority it will need — before it does anything. Approve it or send it back.
  4. Watch it work. Anything outside the task worktree stops and asks.
  5. Review the diff and the evidence behind it. Nothing reaches your branch until you accept it.

Everything CodeFlux stores lives in one directory:

Platform Data directory
Windows %LOCALAPPDATA%\codeflux
macOS ~/Library/Application Support/codeflux
Linux ~/.local/share/codeflux

Delete that directory and CodeFlux is gone. Your repository is not part of it.


What it does differently

Atoms are kept, and re-verified before they are reused

A verified atom carries its purpose, inputs, outputs, algorithm, and the metadata a later run needs to find it. Documentation is written after the tests, the fuzzing, and the mutation score, so it describes what the atom is known to do rather than what its author meant.

A later task looking for the same contract recalls that atom instead of writing a new one — but only if it still passes the tests the new run derived from the new contract. An atom that fails re-verification is rebuilt. Molecules are registered the same way, because a registry holding only leaf functions makes every run rebuild the joins.

This half is built, not demonstrated. Runs decompose, establish atoms with evidence, and register them — that part is exercised. But no run has yet recalled an atom that another run wrote. Ladder runs have reported 0 of N produced atoms reached the registry and a recall stage that searched 0 earlier artifacts; two runs on 2026-08-08 did register their atoms, so registration works at least sometimes. Until a run reuses one, compounding is a design and the paragraph above describes intended behaviour. Tracked as LAD-002.

It never edits your checkout

Every task runs in its own Git worktree. You keep working while a task runs, and nothing the agent does appears in the files you have open. A finished task produces a diff plus the evidence behind it — what changed, which checks ran, what they said. Accepting merges it. Until then, nothing has moved.

Rejecting a task preserves its patch instead of discarding it, so you can still inspect work you decided not to take. Worktrees are cleaned up on a terminal state — except one whose task ended ambiguously, which is kept, because deleting it would destroy the only record of what happened.

Repair is bounded, not a retry loop

When a validation fails, CodeFlux proposes a bounded repair rather than trying again and hoping. A repair resets the approval attached to the plan it changes, because evidence gathered against the old plan no longer describes what will run.

Money is exact, and unknown means unknown

Three things that are easy to confuse are kept apart: a forecast (an estimate, shown as a range, never treated as a commitment), an actual cost (what the provider charged), and unknown (the provider has not reported a price). Unknown is never rendered as zero — a total that quietly counted unknown as nothing would understate your spend exactly when it matters most.

All amounts are exact integer minor units. There is no floating point anywhere in a cost. A hard budget stops new paid work when reached, lets in-flight work settle, and leaves the task resumable. You raise the limit, finish, or stop; CodeFlux does not decide for you.

Memory that can be invalidated

CodeFlux remembers repository facts, reviewed commands, file-to-test mappings, and conventions between tasks. An item is used only when it applies — same project, same toolchain, same dependencies, evidence still holding. Similarity is never treated as applicability: an item that looks relevant is not thereby eligible.

Items record what they were derived from versus what merely influenced them, and the distinction has teeth. Invalidating an item automatically quarantines everything derived from it, because those conclusions depended on it; things it only influenced are flagged for review. A quarantined item can never regain authority — a new item must be established instead.

Vector search is off unless measured retrieval recall justifies turning it on, and even then it proposes candidates only. It never confers eligibility, validity, or permission.

Crash recovery that admits what it cannot know

If CodeFlux, a worker, or your machine dies mid-task, the next start tells you three things separately: what is known (the last durable checkpoint), what is ambiguous (for example, whether a command that reached an external system completed), and what it recommends.

When an external effect's outcome cannot be determined, you must reconcile it before anything else proceeds. CodeFlux will not retry an ambiguous external effect on your behalf — a duplicate charge, deployment, or message is not something it can take back.

Your data stays one file you can inspect

codeflux backup --output <path>        # consistent snapshot, while running;
                                       # never overwrites an existing file
codeflux integrity-check               # structurally sound (not "contents correct")
codeflux diagnostics export --output <path>

A diagnostics bundle carries versions, counts, and statuses — no requirement text, no file contents, no model output — and is scanned before it is written. Database inspection goes through a read-only surface where every entity maps to a fixed parameterised statement; there is no free-text SQL door, and no path that lets an inspection change anything.

Clearing the application log clears the log. Task evidence — events, plans, approvals, validations, diffs — is stored separately and is untouched.


How it works

                      ┌──────────────────────────────────────────┐
   your browser ──────┤  Go → WebAssembly frontend               │
   (loopback only)    │  GoWebComponents v5 · no handwritten JS  │
                      └───────────────────┬──────────────────────┘
                                          │ gRPC over WebSocket
                      ┌───────────────────┴──────────────────────┐
                      │  Coordinator (single process)            │
                      │  plans · authority · budgets · evidence  │
                      └──┬────────────┬──────────────┬───────────┘
                         │            │              │
              ┌──────────┴───┐  ┌─────┴──────┐  ┌────┴─────────────┐
              │ Worker procs │  │ Git        │  │ SQLite           │
              │ no raw creds │  │ worktrees  │  │ sole store       │
              └──────┬───────┘  └────────────┘  └──────────────────┘
                     │
              ┌──────┴────────────┐      ┌──────────────────────────┐
              │ Provider adapters │      │ OS credential store      │
              │ endpoint approval │──────┤ keys never touch SQLite, │
              └───────────────────┘      │ a log, or a worker       │
                                         └──────────────────────────┘

Four decisions explain most of the codebase:

SQLite is the only authoritative store for threads, messages, tasks, events, graphs, atoms, vectors, evidence, budgets, and learned artifacts. No JSON, YAML, or Markdown sidecars for runtime state. One transaction per user-visible outcome.

The frontend is Go. The entire interface compiles to WebAssembly through GoWebComponents v5, talking to the coordinator over gRPC-on-WebSocket via GoGRPCBridge. There is no handwritten JavaScript, TypeScript, HTML, or CSS in the repository, and adding some is a product-boundary violation rather than a style disagreement.

Workers never receive raw provider credentials. They are separate processes with a deliberately narrow environment.

internal/domain imports nothing infrastructural — no SQLite, no provider, no gRPC, no browser, no Git. The domain types are the part that has to stay honest.

Repository layout
Path What lives there
cmd/codeflux The user-facing executable
cmd/codeflux-worker Task worker process
cmd/codeflux-dev Every build, lint, test, and diagnostic gate
internal/domain Stable domain types, infrastructure-free
internal/coordinator Planning, authority, task lifecycle, projections
internal/storage SQLite repositories, transactions, read-only inspection
internal/events Journal and stream contracts
internal/policy, internal/executor Authority derivation and tool execution
internal/gitwork Worktrees, acceptance, rollback
internal/providers Model provider adapters and approved transport
internal/graph, internal/graphlayout Task-scoped execution graph
internal/retrieval, internal/vectorsearch Memory eligibility and candidates
internal/validation, internal/evidence, internal/review Checks and what they prove
internal/forecast, internal/benchmarks Estimates and measurement
internal/redact, internal/credentials Secret handling and scanning
internal/devdiag Profiling and timing — off unless explicitly enabled
web/frontend, web/client The Go/WASM interface
api/proto Service definitions
migrations/ SQL migrations, immutable once merged
.artifacts/ The only place a tool or test may write

How a run produces code

A requirement does not go to a model and come back as a patch. It passes through a declared flow of 37 stages in 7 phases, each with a gate stating what must hold for the stage to count as satisfied.

flowchart TD
    REQ(["Requirement"]) --> A

    A["Phase A · Specification — stages 1–6<br/>deciding what to build"]
    B["Phase B · Atoms — stages 7–17<br/>the smallest independently testable units"]
    C["Phase C · Molecules — stages 18–21<br/>composition, and the obligations it creates"]
    D["Phase D · Control flow — stages 22–25<br/>ordering, termination, every failure path"]
    E["Phase E · Program — stages 26–29<br/>assembly through end-to-end exercise"]
    F["Phase F · Verification depth — stages 30–34<br/>was any of the checking worth anything"]
    G["Phase G · Delivery — stages 35–37<br/>evidence, acceptance, handover"]

    A --> B --> C --> D --> E --> F --> G --> OUT(["Accepted change + evidence"])

    GATE1{"11 · atom-verification"}
    GATE2{"26 · assembly"}
    GATE3{"29 · end-to-end-tests"}
    GATE4{"31 · adversarial"}

    B -.- GATE1
    E -.- GATE2
    E -.- GATE3
    F -.- GATE4

    GATE1 -.-> LOOP
    GATE2 -.-> LOOP
    GATE3 -.-> LOOP
    GATE4 -.-> LOOP

    LOOP{{"Implementation loop<br/>the run's only model entry point"}}
    LOOP -.->|"retry — possibly on a higher rung"| B

    classDef gate stroke-width:2px
    class GATE1,GATE2,GATE3,GATE4 gate
Loading

Three details in that picture matter more than the rest.

Cases come before tests, and tests come before code. Stage 7 derives a ladder of inputs from the signature — straightforward, degenerate, edge, complex, wrong, pathological — before any test is written. A test written by reading an implementation checks what the code does; a case derived from the contract checks what the signature promised. They differ where the bug is.

The order within a phase is deliberate. Anti-pattern detection runs after verification, because a swallowed error is neither a compile error nor a test failure and no test written against current behavior would catch one. Optimization runs after mutation scoring, because rewriting code guarded by tests that have never been shown to detect a defect is how a behavior change ships with a green suite behind it. Documentation comes last, after fuzzing and mutation, so it describes what the atom is known to do rather than what its author meant.

There is exactly one model entry point. The other 36 stages are static analysis, compilation, and running things. Four gates can send work back — atom-verification, assembly, end-to-end-tests, adversarial — and the rung the next attempt runs on is a real choice at each.

The model ladder

A run climbs only when it stalls — three attempts failing identically — not when something fails once.

flowchart LR
    R1["luna : low<br/>default first rung"]
    R2["luna : max"]
    R3["sol : low"]
    R4["sol : high"]
    R5["sol : max<br/>not on the default ladder"]

    R1 -->|stall| R2 -->|stall| R3 -->|stall| R4
    R4 -.->|"must be added, and asks before spending"| R5

    classDef ask stroke-width:2px
    class R5 ask
Loading

Effort is exhausted on the cheap model before the expensive one is touched. Raising effort bills more tokens at the rate already in force; changing model raises the rate on every token. Medium is skipped on each model deliberately — every rung costs a full stall to detect, so a rung only marginally better than the one below it is paid for in attempts and returns nothing.

The top rung is off the default ladder entirely. Reaching it is the point where a run stops being an experiment and becomes a decision about money, so a person adds it and is asked before a run spends it.

Outcomes are five, not two

State Means
satisfied The gate held and the stage produced evidence
failed The gate did not hold
skipped This run had no need of it — a program with no parsing has nothing to fuzz
blocked Something upstream did not happen, which is not the same as this stage failing
not-implemented The product cannot perform this stage at all

That last one exists because collapsing it into skipped would let a build implementing a third of the flow report the same shape of result as one implementing all of it.

The flow is declared; not all of it is performed. internal/pipeline owns the vocabulary only — the ordered stages, the closed set of outcomes, and each stage's gate. It performs nothing and decides nothing about any run. The coordinator performs the stages it can and records the rest as not-implemented, which is the point: a flow whose missing stages are invisible looks identical to one that has none.

All 37 stages
flowchart TD
    subgraph A["A · Specification"]
        direction TB
        a1["1 instructions"] --> a2["2 clarification"] --> a3["3 atomic-instructions"]
        a3 --> a4["4 decomposition-coverage"] --> a5["5 contracts"] --> a6["6 recall"]
    end

    subgraph B["B · Atoms"]
        direction TB
        b1["7 atom-case-synthesis"] --> b2["8 atom-example-tests"] --> b3["9 atom-property-tests"]
        b3 --> b4["10 atoms"] --> b5["11 atom-verification"] --> b6["12 atom-fuzz"]
        b6 --> b7["13 atom-mutation"] --> b8["14 anti-patterns"] --> b9["15 atom-optimization"]
        b9 --> b10["16 atom-complexity"] --> b11["17 atom-documentation"]
    end

    subgraph C["C · Molecules"]
        direction TB
        c1["18 composition-obligations"] --> c2["19 molecule-tests"]
        c2 --> c3["20 molecules"] --> c4["21 molecule-verification"]
    end

    subgraph D["D · Control flow"]
        direction TB
        d1["22 control-obligations"] --> d2["23 control-tests"]
        d2 --> d3["24 control-flow"] --> d4["25 path-coverage"]
    end

    subgraph E["E · Program"]
        direction TB
        e1["26 assembly"] --> e2["27 program"] --> e3["28 integration-tests"] --> e4["29 end-to-end-tests"]
    end

    subgraph F["F · Verification depth"]
        direction TB
        f1["30 global-invariants"] --> f2["31 adversarial"] --> f3["32 repetition"]
        f3 --> f4["33 platform-matrix"] --> f5["34 non-functional"]
    end

    subgraph G["G · Delivery"]
        direction TB
        g1["35 evidence-bundle"] --> g2["36 human-acceptance"] --> g3["37 deliver"]
    end

    a6 --> b1
    b11 --> c1
    c4 --> d1
    d4 --> e1
    e4 --> f1
    f5 --> g1
Loading

Stage numbers order the flow; they are not identity. Inserting a stage shifts every number after it, which is why the ledger records a stage's name beside its number. A number answers "how far did this get"; only the name answers "which check was this".


What it will not do

These are documented limits, not gaps waiting to be filled. Read them before deciding what to use CodeFlux for.

CodeFlux is not a security sandbox. A command you approve runs as your user, with your files and your network. CodeFlux controls what gets proposed and what you are asked about; it does not contain what runs after you say yes. Container isolation is designed but not enabled. Do not use CodeFlux as a boundary against code you do not trust.

  • Prompt injection is mitigated, not solved. Structural authority closes the direct path. It does not make a model immune to being misled about what to propose — which is exactly why the approval step exists and why it shows you the exact action.
  • Evidence is bounded by what was checked. A green validation means those commands passed. Nothing more is claimed.
  • The graph is an explanation, not a proof. It is projected from recorded events. Nothing in CodeFlux treats a graph node as evidence, and neither should you.
  • External systems may violate their contracts. Providers report usage late or not at all; APIs act and then fail to respond. CodeFlux stays honest when this happens — it will tell you an outcome is unknown rather than guess — but it cannot make an external system behave.
  • Single machine, single user. No multi-user model, no shared state, no server deployment. The coordinator binds loopback only.
  • Go-first. Non-Go repositories open as explicitly labeled experimental inputs until a language-specific mapping and validation contract exists.
  • At most four active tasks, and at most one active task per repository.

Deliberately deferred, so their absence is a decision rather than an oversight: container and VM isolation · multi-user and team features · deep verification (formal methods, property inference, semantic diffing) · hosted or remote operation · automatic updates — an agent that can change your repository and hold your credentials must not also replace its own executable unasked · provider fallback and routing · atom reuse at scale, which has a stated kill criterion because whether reuse pays for itself is the open question the prototype exists to answer.


Project status

Prototype. No stable release yet. Milestones 00–23 are complete — 1,846 tasks covering the runtime, storage, transport, interface, graph, memory, validation, harness, and local hardening. Milestone 24, the end-to-end vertical slice and prototype exit, is roughly half done.

Expect breaking changes. Expect the database schema to move. Do not point this at a repository you cannot afford to review carefully.

Where the two bets actually stand, since the idea is the reason to read any of this:

Bet State
Decomposition into verified atoms Exercised. Runs plan a layout from the requirement, produce atoms with contracts and evidence, and pass the full 41-stage gate set. Not yet measured against a one-pass baseline.
Verified reuse compounds Built, not demonstrated. No run has recalled an atom another run wrote (LAD-002). Registration works at least sometimes; recall has never fired.

Neither has been measured against a control arm yet, so nothing here is a performance claim. The number that would settle it — marginal cost per comparable task, falling as atoms accumulate — does not exist.

Supported platforms

CI is authoritative. A platform without passing CI is experimental, not supported.

Platform Status
Windows 11 ARM64 Full quality gate + build
Windows Server 2025 AMD64 Fast tests + build
macOS 15 ARM64 Fast tests + build
Ubuntu 24.04 AMD64 Fast tests + build + race detector

Development

Requires Go 1.26.0+ and Git. Nothing else to build.

git clone https://github.com/monstercameron/CodeFlux.git
cd codeflux
go run ./cmd/codeflux-dev bootstrap     # verify and pin development tools
go run ./cmd/codeflux-dev test-fast     # the default suite
go run ./cmd/codeflux-dev build

git config core.hooksPath .githooks     # run the lint gate before each commit
Command Gate
lint gofmt + vet + staticcheck + secret scan
generate-check generated output is current
test-fast / test-integration / test-race correctness
test-security abuse suites
test-browser mounted browser harness
test-coverage coverage
migration-check migration catalog consistency
artifact-check artifact boundary + credential scan
benchmark performance measurement

None of these reach the network. The single command that does — run-live — is deliberately excluded from every suite, so an ordinary test run can never spend your money or depend on a provider being up.

CI invokes these same commands by the same names, and a test (TestM22_124_LocalAndCIShareTheSameCommandGraph) enforces the correspondence — a gate that existed only in the workflow would be a gate nobody could run before pushing.

Two rules surprise people. .artifacts/ is the only place a tool may write, and artifact-check fails the build when something escapes. And a passing run writes nothing at all, because an artifact directory full of successes is noise nobody reads; an artifact means something failed.


Documentation

Document For
docs/using.md Installing, providers, permissions, budgets, recovery, limitations
docs/developing.md Failure artifacts, session replay, safe DB inspection, profiling, golden paths
docs/storage.md Schema and durability
docs/benchmarks.md What is measured and how
docs/plan.md The full design argument — authoritative for product intent, architecture, and scope
AGENTS.md Repository-wide rules — authoritative for how changes are made
TODOS.md Dependency order and completion state
CHANGELOG / DEVLOG Commit outcomes and implementation chronology

Contributing

Please read .github/CONTRIBUTING.md first — this repository is governed more tightly than most its size, and a patch that ignores the governance is declined no matter how good the code is. Open an issue before writing anything.

Security issues go to private reporting, never a public issue. See .github/SECURITY.md for what is in scope — in particular, "an approved command did something bad" is documented behavior, while "an unapproved command ran" is a vulnerability.

Much of this repository was written by a coding agent, which is expected to continue. If you use one, point it at AGENTS.md first; the rules are not discoverable from the code alone, and a capable agent that has not read them will produce a confident, well-tested, unmergeable patch.

License

MIT © 2026 Earl Cameron

About

Verified atoms. Better software. An experimental coding agent that assembles programs out of small, separately verified pieces instead of writing them in one pass — authority comes from what an action is, not from what the model claims it needs.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages