Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ repos:
pass_filenames: false
files: ^(crucible/src/plan/starlark|docs/dsl-reference\.md)

- id: loop-docs
name: regenerate the loop state machine page
entry: scripts/loop-docs.sh
language: system
pass_filenames: false
files: ^(crucible/src/machine\.rs|docs/loop-machine\.md)

- id: gov-render
name: render RFCs from the governance SSOT
entry: govctl render rfc
Expand Down
6 changes: 5 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ whether the code works.
values become newtypes whose only constructor is the check
(`RepoTarget` via `OrgAllowlist::authorize` is the house style: a checked
value is a type, so an unchecked one cannot reach the call).
- Put behavior on the domain type that owns the state or specification it acts
on. Prefer `gate.attempt(...)`, `source.resolve(...)`, and `host.suspend(...)`
over free functions that take the owner as their first argument; keep a free
function only when no domain type owns the operation.
- Groups of adjacent scalars in a signature become a struct; mode-dependent
knobs become an enum keyed by mode. Repeated inline conversions become
`From`/`TryFrom` impls next to the types.
Expand All @@ -80,7 +84,7 @@ whether the code works.
## PRs, commits, comments

- Never put an AI session link in a PR body, PR description, or commit
message. Commits carry a plain `Assisted-by: Claude` trailer.
message.
- Agents never post PR comments, review replies, or issue comments; those would
appear under the operator's account. Report dispositions in the driving
session instead.
Expand Down
1 change: 1 addition & 0 deletions CLAUDE.md
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ The main manifest sections are:
| `[agent]` | yes | Configures the backend, harness, model, goal, prompt, environment, and sandbox. |
| `[judge]` | no | Defines `measure_cmd`, score `direction`, and optional gate self-tests. Omitted entirely, the run is a task: every completed turn is kept, unscored (see [docs/task-lane.md](docs/task-lane.md)). |
| `[world]` | no | Adds apply, snapshot, and restore commands for state outside Git. |
| `[search]` | no | Configures a parallel wide round before the iterative deep loop. |
| `[workflow]` | no | Defines the task graph used by an iteration. |
| `[deploy]` | no | Defines build and deployment values used by rendered cluster runs. |
| `[build.<name>]` | no | Defines a named image build target. |
Expand Down Expand Up @@ -328,12 +327,14 @@ Running `crucible` without a subcommand starts an optimization loop and requires
| `crucible plan show` | Validates and displays a work-graph plan. |
| `crucible plan run` | Executes a plan with the shell runner or a manifest-backed agent. |
| `crucible watch-pr` | Converts authorized pull-request review comments into live steering or a reseed file. |
| `crucible approve` / `crucible deny` | Resolves the approval gate a live run is parked on, over its control bridge. |
| `crucible fetch-resume` | Restores a suspended run's session log and workspace from the controller before resuming it. |
| `crucible fetch` | Downloads one exact S3 object URI to a local file. |
| `crucible rank-grounded` | Performs one read-only, code-grounded ranking turn over an existing checkout. |
| `crucible build` | Executes a named build configuration and prints the resulting digest-pinned image reference. |

Common loop controls include `--iterations`, `--wide`, `--wide-keep`, `--max-cost`,
`--max-time`, `--ui`, `--resume`, and `--no-early-stop`.
Common loop controls include `--iterations`, `--max-cost`, `--max-time`, `--ui`, `--resume`,
and `--no-early-stop`.

## Repository layout

Expand Down
1 change: 1 addition & 0 deletions crucible-contract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition.workspace = true
[dependencies]
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
# Tier 2 content-addressing: engine and controller MUST compute the same `sha256:<hex>` digest,
# so the one spelling lives here where both sides call it.
sha2 = "0.10"
23 changes: 20 additions & 3 deletions crucible-contract/src/artifact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use std::fmt;
use std::fmt::Write as _;
use std::str::FromStr;

const MIB: u64 = 1024 * 1024;
const KIB: u64 = 1024;
const MIB: u64 = 1024 * KIB;

/// The content digest of an artifact's (compressed) bytes, `sha256:<lowercase-hex>`. Both the
/// engine and the controller drop-box call this, so the two digests are byte-for-byte comparable
Expand All @@ -28,7 +29,8 @@ pub fn content_digest(bytes: &[u8]) -> String {
}

/// The Tier 2 artifact kinds. The serde spelling is the `{kind}` path segment of the ingest route
/// (`scope-pack`, `scope-transcript`, `run-session`, `run-files`, `otel-log`).
/// (`scope-pack`, `scope-transcript`, `run-session`, `run-files`, `run-workspace`,
/// `approval-waits`, `otel-log`).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum ArtifactKind {
Expand All @@ -40,6 +42,11 @@ pub enum ArtifactKind {
RunSession,
/// The gzipped tar of a loop run's `state/files`, one directory per task that captured.
RunFiles,
/// The gzipped tar a suspended run leaves for its resume: `state/` minus the session log,
/// a bundle of the workspace repo, and `state/resume.json`.
RunWorkspace,
/// The JSON list of approval gates a parked run is waiting on, replaced on every change.
ApprovalWaits,
/// The raw OTLP jsonl the in-process collector captured next to the agent.
OtelLog,
}
Expand All @@ -52,6 +59,8 @@ impl ArtifactKind {
ArtifactKind::ScopeTranscript => "scope-transcript",
ArtifactKind::RunSession => "run-session",
ArtifactKind::RunFiles => "run-files",
ArtifactKind::RunWorkspace => "run-workspace",
ArtifactKind::ApprovalWaits => "approval-waits",
ArtifactKind::OtelLog => "otel-log",
}
}
Expand All @@ -63,16 +72,20 @@ impl ArtifactKind {
ArtifactKind::ScopeTranscript => 32 * MIB,
ArtifactKind::RunSession => 128 * MIB,
ArtifactKind::RunFiles => 256 * MIB,
ArtifactKind::RunWorkspace => 32 * MIB,
ArtifactKind::ApprovalWaits => 64 * KIB,
ArtifactKind::OtelLog => 32 * MIB,
}
}

/// Every kind, for exhaustive iteration in tests and route registration.
const ALL: [ArtifactKind; 5] = [
const ALL: [ArtifactKind; 7] = [
ArtifactKind::ScopePack,
ArtifactKind::ScopeTranscript,
ArtifactKind::RunSession,
ArtifactKind::RunFiles,
ArtifactKind::RunWorkspace,
ArtifactKind::ApprovalWaits,
ArtifactKind::OtelLog,
];
}
Expand Down Expand Up @@ -172,6 +185,8 @@ mod tests {
assert_eq!(ArtifactKind::ScopePack.as_str(), "scope-pack");
assert_eq!(ArtifactKind::ScopeTranscript.as_str(), "scope-transcript");
assert_eq!(ArtifactKind::RunSession.as_str(), "run-session");
assert_eq!(ArtifactKind::RunWorkspace.as_str(), "run-workspace");
assert_eq!(ArtifactKind::ApprovalWaits.as_str(), "approval-waits");
assert_eq!(ArtifactKind::OtelLog.as_str(), "otel-log");
}

Expand All @@ -180,6 +195,8 @@ mod tests {
assert_eq!(ArtifactKind::ScopePack.max_bytes(), 16 * MIB);
assert_eq!(ArtifactKind::ScopeTranscript.max_bytes(), 32 * MIB);
assert_eq!(ArtifactKind::RunSession.max_bytes(), 128 * MIB);
assert_eq!(ArtifactKind::RunWorkspace.max_bytes(), 32 * MIB);
assert_eq!(ArtifactKind::ApprovalWaits.max_bytes(), 64 * KIB);
assert_eq!(ArtifactKind::OtelLog.max_bytes(), 32 * MIB);
}

Expand Down
Loading
Loading