Skip to content

About

Execution and governance for agentic software engineering: sealed workflows, durable human collaboration, and proof-carrying Git changes.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Constructicon

verify Python 3.11+ License: MIT

Assemble the plan. Seal the run. Prove what ships.

Constructicon is an execution and governance layer for agentic software engineering: sealed workflows, durable human collaboration, and proof-carrying Git changes.

Agents propose work and compose its structure. Constructicon validates that proposal, pins what will execute, scopes its capabilities, and records the evidence for external changes. Humans observe, advise, and approve through the same typed control plane.

Authored intent may be ergonomic. Executed reality must be explicit.

Developer preview. M1 through M7.1 are complete, and M8 (live executors) reached its bounded closure: executor contracts, networkless Linux containment, contained WRITE capture and gates, and three adapters with recorded evidence. Codex and Claude Code have accepted historical subscription READ and WRITE evidence; Pi has a qualified bounded local READ profile. M9 (self-improvement through evaluated candidates) delivered its bounded first phase: an installed fixed selector trial, run live once through owner approval, promotion and rollback. None of this enables a generally available production provider. See current status and open work.

Why Constructicon exists

An agent's proposal, a successful check, a human approval, and an installed change are different facts. Constructicon keeps the relationships between them explicit and recoverable:

What exact plan ran, against which component world, what evidence passed, what changed, and can the answer survive a crash or retry?

The model may change. The execution, recovery, and authority laws do not move into the model or its provider.

The central promise

Within Constructicon's Git authority, proposed code reaches a protected ref through one exact, attested, idempotent Git transaction.

Gates run against the prepared merge commit into the current base. merge_verified installs that exact commit. A moved base, missing evidence, forged result, mismatched subject, or failed check moves nothing.

How it works

Agent, MCP client, or Python SDK
                |
                v
        strict Ref | Graph | Loop
                |
                v
     admission and typed rejection
                |
                v
       sealed ExecutionManifest
                |
                v
 capability-scoped, journaled execution
                |
                v
 CheckResult -> Attestation -> EffectReceipt
                |
                v
       exact verified Git transaction

Agents may author the work and its structure. They do not get to decide that their own work is safe, mint their own proof, or grant themselves more authority.

Core guarantees

  • Intent compiles. Execution is sealed. Admission resolves references, bindings, versions, loops, and grants into one immutable manifest. The walker executes only that manifest.
  • Authority is physical. LLMs propose. Deterministic code validates, executes, reconciles, and disposes.
  • Effects carry proof. Irreversible actions require a journal-minted attestation for the exact subject and sealed world.
  • Crashes are normal. Completed invocations resume from checkpoints. Unknown external outcomes are reconciled before anything is repeated.
  • Versions do not drift. Definitions are immutable, runs pin one world_hash, and new versions affect future runs only through promotion.
  • Learning produces candidates, never mutations. A component cannot rewrite itself, promote itself, or define its own exam.

Humans are participants, not side channels

Journal-backed mailboxes carry typed requests, replies, and acknowledgements. A run can park while waiting for advice or approval, release its invocation resources, and wake from the durable reply after a process restart. Advice and approval have separate authority; a human decision does not replace evidence from deterministic checks.

panel() composes ordinary graph nodes with explicit membership and mapped fan-in. The standard quorum aggregator evaluates typed member results under an explicit policy. Human members use the same channel contracts; there is no panel-specific scheduler. See channels and panels.

One executor seam, multiple kinds of backend

Claude Code, Codex, and Pi are the initial integration targets, not a closed provider list. Future cloud APIs and local models can enter through compatible task harnesses implementing the existing Executor / ExecutorProvider contracts. Provider configuration, authentication, and native stream decoding belong in the adapter; the graph language and walker do not grow provider switches. An adapter is interchangeable only where it can enforce the admitted capabilities.

Subscription reuse has bounded, revision-specific historical evidence for Codex and Claude Code, not general production availability. Pi's evidence is a pinned local model on a disposable hosted Linux runner, not a vendor account. Accepted ADR 0021 selects an operator-bound subscription route for the explicit v3 profile; gateway v1 under ADR 0018 is unchanged and unselected. The authentication record holds the evidence; nothing authorizes copying desktop credentials or silently substituting API billing. See adding an executor.

Quick start

Constructicon currently targets Python 3.11 or newer and uses uv for development. In Bash/Git Bash:

git clone https://github.com/sushiHex/constructicon.git
cd constructicon
uv sync --dev --python 3.11
PYTHONIOENCODING=utf-8 uv run verify

The setup command selects standard CPython 3.11, matching the primary CI interpreter, rather than an arbitrary installed interpreter variant. This does not change the package's Python 3.11+ requirement. In PowerShell, use the same setup commands, then $env:PYTHONIOENCODING = "utf-8" followed by uv run verify.

verify runs the same credential-free gate as CI: Ruff, strict mypy, import-linter, and pytest.

The separate Linux containment lane provisions its physical test boundary on GitHub Actions. Platform skips in a local run are not containment evidence.

To follow a proposed change through capture, trusted checks and recorded acceptance or refusal, run the existing credential-free maintenance rehearsal. It uses scripted native input and disposable Git state, not a model login or your working repository as a merge target.

For a runnable workflow that compares committed Python changes, parks for operator advice and completes after a process restart, follow the durable change-review example. It needs no model login and reports the existing metering fields without inventing usage or cost.

Run a small workflow

This example executes a deterministic Python task. It needs no model login, executor service, or protected Git repository.

Definitions must be importable after restart. Create demo_component.py in the repository root:

from typing import Annotated

from pydantic import BaseModel

from constructicon.sdk import port_type, task


class Issue(BaseModel):
    title: str


class Brief(BaseModel):
    title: str


@task("demo/triage", output="brief")
async def triage(
    issue: Annotated[Issue, port_type("demo/Issue")],
) -> Annotated[Brief, port_type("demo/Brief")]:
    return Brief(title=issue.title)

Then create demo.py:

import asyncio
from pathlib import Path

from constructicon.api.control import ControlPlane
from constructicon.api.system import Constructicon
from constructicon.core.control import (
    ADMIN_SCOPE,
    OPERATE_SCOPE,
    READ_SCOPE,
    AuthenticatedActor,
    PromotionCommandResult,
    RegistrationCommandResult,
    RunResultPreviewV3,
    RunSubmission,
)
from constructicon.core.run import RunStatus
from constructicon.sdk import flow
from constructicon.substrate.journal.sqlite import SqliteJournal
from demo_component import triage


async def main() -> None:
    state_dir = Path(".constructicon")
    state_dir.mkdir(exist_ok=True)

    journal = SqliteJournal(state_dir / "demo.db")
    system = Constructicon(journal=journal)
    control = ControlPlane(system=system, store=journal)
    launcher = AuthenticatedActor(
        actor_id="static:demo-launcher",
        auth_method="static",
        scopes=frozenset({READ_SCOPE, OPERATE_SCOPE, ADMIN_SCOPE}),
    )
    await control.startup()
    try:
        registered = await control.registry_register(
            launcher,
            definition=triage,
            idempotency_key="demo-register-triage-v1",
        )
        assert isinstance(registered, RegistrationCommandResult)
        promoted = await control.registry_promote_initial(
            launcher,
            component=registered.component,
            version=registered.version,
            idempotency_key="demo-promote-triage-v1",
        )
        assert isinstance(promoted, PromotionCommandResult)

        workflow = flow("demo/issue-to-brief", triage)
        submitted = await control.runs_start(
            launcher,
            proposal=workflow.definition.body,
            inputs={"issue": {"title": "Fix the flaky retry"}},
            idempotency_key="demo-run-1",
        )
        assert isinstance(submitted, RunSubmission)
        async with asyncio.timeout(30):
            while True:
                result = control.runs_result(launcher, submitted.run_id)
                assert isinstance(result, RunResultPreviewV3)
                if result.status not in (RunStatus.PENDING, RunStatus.RUNNING):
                    break
                await asyncio.sleep(0.05)
        assert result.status is RunStatus.SUCCEEDED, result.model_dump_json()
        print(result.status.value, result.outputs)
    finally:
        await control.shutdown()


asyncio.run(main())

Run it:

uv run python demo.py

Expected output:

succeeded {'brief': {'title': 'Fix the flaky retry'}}

Run the unchanged example again to replay the same command keys and read the same completed run. If you change a command's arguments, give that operation a new idempotency key; reusing a key with a different request is a refusal.

@task, flow, component, harness, loop, and panel are authoring sugar only. They immediately lower to the same canonical Ref | Graph | Loop contracts used by strict agent-authored JSON. There is no privileged SDK workflow model and no trusted bypass around admission.

Agent control through MCP

Install the optional MCP adapter and start a local stdio control plane:

uv sync --extra mcp --dev
uv run constructicon-mcp \
  --database .constructicon/constructicon.db

The MCP adapter is a thin transport over the same typed ControlPlane. Mutating operations require caller idempotency keys, bounded responses use revision-pinned pagination, and full immutable records remain available by reference. Local registration and initial promotion are intentionally Python launcher operations, not MCP tools.

The CLI does not provision executor or channel capabilities. Assemble those in a Python launcher; persisted definitions do not substitute for live capability bindings. The same MCP surface exposes human inboxes, replies, acknowledgements, and request-bound approvals under the actor's scopes.

For HTTP, Constructicon is authenticated or unavailable. Actor identity comes from a verified OAuth bearer token, never from a caller-controlled tool argument.

What is implemented

Constructicon 0.1.0 is a developer preview, not a hosted coding-agent service. The execution and authority laws are governed by the invariants and accepted ADRs. Milestones M1 through M7.1 are complete, and M8 and M9 each closed a bounded scope:

Milestone Capability
M1 Sealed manifests, checkpoint resume, and idempotent effects
M2 Persistent registry, crash hardening, cancellation, liveness, and projections
M3 Protected Git authority, real gates, attestations, and exact verified merge
M4 Generic bounded repair loops without a second scheduler
M5 Agent-first JSON authoring, SDK sugar, introspection, and repairable admission
M6 Durable authenticated command law, race-safe hosting, revision-pinned reads, MCP v2 adapter, and counterfactual replay
M7 Durable channels, human advice and approval, restart-safe waiting, and deterministic panels
M7.1 Explicit panel membership, ordered mapped fan-in, exact endpoint diagnostics, and strengthened counterfactual admission
M8 (bounded closure) Executor policy and launch identity, networkless Linux containment, contained WRITE capture and gates, and Codex, Claude Code and Pi adapters with bounded evidence
M9 (bounded first phase) A fixed self-improvement trial, run live once: catalog selection, scripted exam, owner approval, journal proof, promotion and rollback

M8: live executors

M8 closed under the bounded acceptance recorded in #42. It includes complete executor grant policy, content-bound launch identity, record-before-materialization leases, a networkless Linux launcher, owned READ/WRITE workspaces, and process cleanup that survives controller death. Failure of the trusted reaper itself is outside that recovery guarantee. The physical boundary is tested on GitHub Actions with hostile fixtures, not live model calls. Async WRITE capture runs staging Git inside that boundary, verifies an immutable pack, and atomically fences its exact candidate against acquisition closure.

Contained async gates use the same boundary to check the exact prepared merge snapshot. Runtime identification happens without a candidate mount; cancellation and descendant cleanup complete before authority is minted.

The Codex subscription adapter follows ADR 0021. Its implementation includes:

  • a strict READ and WRITE operator adapter for the pinned client;
  • operator-store custody with offline maintenance and activation;
  • vendor egress through a host relay limited to the sealed vendor destinations, for one acquisition at a time;
  • installation on a private Linux host from reviewed artifacts only;
  • an authenticated-startup lane under the owner's operator_authorized overage bound: the account's own settings bound spend, and Constructicon enforces no ceiling. It starts no turn while the account reports its spend control reached, and publishes the readback facts.

Credential-free CI exercises hostile fixtures. Separately authorized historical host sessions established bounded Codex READ and WRITE at distinct revisions and measured explicit refresh. Natural expiry-triggered refresh and actual live expired-login behavior remain unmeasured. See the accepted historical closeout.

The later q13 maintenance application was accepted, and its data-only parser vectors were recovered into an ordinary contribution in PR #250. The recovery record separates the historical exam from current-source regression evidence.

A second fixed maintenance task, the stored-reply extraction, had one authorized live attempt (#397). The application completed normally and accepted no candidate: the writer was refused as capture-unchanged, because the attempt left the target at its base. The window then withdrew its generation, parked the host and released custody, with no retry (outcome record). The follow-up is open as #407, the one open issue in the M8 milestone. Merged so far: instructions that name the one write tool, where it runs and what is captured (#408) and state the guards that end an attempt (#411); the retained first request of a maintenance WRITE turn (#409); retained digests and lengths of an attempt's callback content and reply (#410); and model-shaped replies pinned to their refusals (#412). None of these shows that a model now writes; only a further authorized attempt can.

Claude Code is the independent second subscription adapter (#40). Its fixed pre-dispatch startup predicate, admitted READ composition and contained WRITE callback, capture and gate path were qualified, followed by one authorized live subscription READ and one live WRITE at recorded revisions.

Pi has a qualified bounded local READ profile: pinned Pi with a small local model on a disposable hosted Linux runner, one correlated READ with an unchanged workspace and joined teardown. That smoke does not establish live Pi through ControlPlane. The same workspace component runs unchanged through ControlPlane and RunHost under scripted Claude Code and Pi bindings; Codex's no-workspace profile is refused before dispatch. The composed contained WRITE proof installs the attested merge commit, reconciles an interrupted install without a second write, and keeps malformed READ output from checkpointing. See the bounded integration acceptance.

These results do not auto-enable a provider, supply general vendor conformance, or qualify another boot: fresh continuity and qualification remain required. The gateway route (#39) and OpenRouter (#47) remain unselected, and both are tracked outside the M8 milestone. See the implementation record for current evidence and the authentication assessment for the route decision and its historical investigation.

M9: self-improvement (bounded first phase)

M9 learns through evaluated immutable candidates and explicit promotion, without letting the learner define its own exam (design, plan, #45).

The first phase is deliberately narrow. The installed fixed selector trial (python -m constructicon.api.m9_trial) asks a Codex READ to choose one entry from a finite reviewed instruction catalog. A fixed scripted diagnostic exam then evaluates the choice, the owner approves or rejects the exact candidate edge through the durable approval channel, and the issuer mints journal proof before any promotion. Promotion, its replay and rollback act only on that exact edge. The trial survives operator process restarts, and a credential-free rehearsal runs it with the shipped fake executor.

The bounded live trial completed end to end, closing #45: an owner-approved Codex READ selected cite-evidence, the owner approved the exact candidate, proof was issued, and promotion and rollback each ran with a replay before an independent read confirmed the stable pointer back at the baseline (live record). This proves the lifecycle, not improved answers: the exam measures scripted behavior, not prompt quality on real model answers, and free-form prompt bytes remain deferred.

When Constructicon fits

Constructicon is aimed at solo developers, teams, and researchers building agent-driven workflows over real repositories.

It is a good fit when you need:

  • restart-safe, long-running software workflows
  • exact provenance for code, checks, versions, and external effects
  • an authority boundary independent of the model or agent provider
  • reproducible and counterfactual runs against a recorded component world
  • machine-shaped APIs with typed, repairable rejection
  • durable human advice, approvals, and explicitly composed panels
  • protected Git changes that are exact, attested, and idempotent

It is not a hosted coding-agent product, a prompt framework, or a general model router.

The conceptual kernel

Almost every execution concept reduces to four nouns:

Noun Meaning
Definition What may be reused
Manifest What this run will execute
Invocation Where one execution occurred
Receipt What changed outside the run

Everything else is a policy that transforms or admits these, a transport that carries them, a projection that renders them, or a capability leased to execute them.

Architecture

L4  api        ControlPlane, RunHost, MCP, system assembly
L3  sdk        @task, component, flow, harness, loop, panel
L2  runtime    registry, admission, manifest, walker, resume
L1  substrate  journal, Git authority, workspaces, gates, executors, effects, channels
L0  core       every contract in the system, defined once

Dependencies point toward contracts. The runtime never imports concrete substrate implementations, and the kernel is limited to the standard library plus Pydantic. CI enforces both rules.

Documentation

Contributing

Contributions are welcome, especially around real executor integrations, failure probes, channel transports, and examples.

Find ready work or propose an issue. Read how we track work before starting a substantive change so contributors and agent sessions share one queue.

Before adding a new concept, read the invariants, inspect system.describe(), and look for an existing contract to compose. The full repository gate is one command:

uv run verify

The expected standard is simple: if a failure can happen between two durable facts, test the crash there.

License

MIT. See LICENSE.

About

Execution and governance for agentic software engineering: sealed workflows, durable human collaboration, and proof-carrying Git changes.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages