From 0ae1e381b87ea815f0d4ca66689db10bb1129e4a Mon Sep 17 00:00:00 2001 From: Ompragash Date: Thu, 23 Jul 2026 05:07:56 +0530 Subject: [PATCH 1/2] docs: build complete agentctl documentation system --- .github/workflows/ci.yml | 3 + CODE_OF_CONDUCT.md | 17 + README.md | 2 +- SECURITY.md | 17 + docs/ARCHITECTURE.md | 2 +- docs/CONTRIBUTING.md | 74 ++++- docs/OBSERVABILITY.md | 41 ++- docs/OPERATIONS.md | 2 +- docs/architecture/DIAGRAMS.md | 290 ++++++++++++++++++ docs/development/ADD_ACTION.md | 41 +++ docs/development/ADD_MIGRATION.md | 23 ++ docs/development/ADD_PROVIDER.md | 35 +++ docs/development/DOCUMENTATION.md | 41 +++ docs/development/REPOSITORY.md | 63 ++++ docs/guides/CI_CD.md | 66 ++++ docs/guides/FIRST_AGENT_WORKFLOW.md | 83 +++++ docs/guides/GETTING_STARTED.md | 86 ++++++ docs/guides/INSTALLATION.md | 71 +++++ docs/guides/LOCAL_OPERATION.md | 69 +++++ docs/guides/TROUBLESHOOTING.md | 134 ++++++++ docs/guides/WORKFLOW_AUTHORING.md | 123 ++++++++ docs/reference/CLI_OUTPUT.md | 38 +++ docs/reference/DATABASE.md | 41 +++ docs/reference/ENVIRONMENT_AND_PATHS.md | 44 +++ docs/reference/MATRICES.md | 39 +++ docs/reference/TERMINOLOGY.md | 27 ++ docs/reference/YAML.md | 108 +++++++ docs/use-cases/APPROVAL_GATED_ACTION.md | 36 +++ docs/use-cases/CI_QUALITY_GATE.md | 32 ++ docs/use-cases/PROVIDER_PORTABILITY.md | 47 +++ docs/use-cases/RECORDED_REPLAY.md | 34 ++ docs/use-cases/RELEASE_READINESS.md | 32 ++ docs/use-cases/REPOSITORY_AUDIT.md | 39 +++ docs/use-cases/SCHEDULED_REVIEW.md | 35 +++ examples/README.md | 5 + examples/custom-pack-tools/README.md | 28 +- examples/dataflow/README.md | 26 +- examples/docs/README.md | 13 + examples/docs/ci-quality-gate/workflow.yaml | 26 ++ examples/docs/provider-portability/fake.yaml | 27 ++ .../docs/provider-portability/openai.yaml | 31 ++ examples/docs/release-readiness/workflow.yaml | 45 +++ examples/docs/scheduled-review/workflow.yaml | 32 ++ examples/memory-flow/README.md | 36 +-- examples/prompt-cache/README.md | 40 +-- examples/prompt-file-vars/README.md | 29 +- examples/real-autonomy/README.md | 46 +-- examples/remote-mcp-autonomy/README.md | 41 +-- xtask/src/main.rs | 250 ++++++++++++++- 49 files changed, 2274 insertions(+), 236 deletions(-) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 SECURITY.md create mode 100644 docs/architecture/DIAGRAMS.md create mode 100644 docs/development/ADD_ACTION.md create mode 100644 docs/development/ADD_MIGRATION.md create mode 100644 docs/development/ADD_PROVIDER.md create mode 100644 docs/development/DOCUMENTATION.md create mode 100644 docs/development/REPOSITORY.md create mode 100644 docs/guides/CI_CD.md create mode 100644 docs/guides/FIRST_AGENT_WORKFLOW.md create mode 100644 docs/guides/GETTING_STARTED.md create mode 100644 docs/guides/INSTALLATION.md create mode 100644 docs/guides/LOCAL_OPERATION.md create mode 100644 docs/guides/TROUBLESHOOTING.md create mode 100644 docs/guides/WORKFLOW_AUTHORING.md create mode 100644 docs/reference/CLI_OUTPUT.md create mode 100644 docs/reference/DATABASE.md create mode 100644 docs/reference/ENVIRONMENT_AND_PATHS.md create mode 100644 docs/reference/MATRICES.md create mode 100644 docs/reference/TERMINOLOGY.md create mode 100644 docs/reference/YAML.md create mode 100644 docs/use-cases/APPROVAL_GATED_ACTION.md create mode 100644 docs/use-cases/CI_QUALITY_GATE.md create mode 100644 docs/use-cases/PROVIDER_PORTABILITY.md create mode 100644 docs/use-cases/RECORDED_REPLAY.md create mode 100644 docs/use-cases/RELEASE_READINESS.md create mode 100644 docs/use-cases/REPOSITORY_AUDIT.md create mode 100644 docs/use-cases/SCHEDULED_REVIEW.md create mode 100644 examples/README.md create mode 100644 examples/docs/README.md create mode 100644 examples/docs/ci-quality-gate/workflow.yaml create mode 100644 examples/docs/provider-portability/fake.yaml create mode 100644 examples/docs/provider-portability/openai.yaml create mode 100644 examples/docs/release-readiness/workflow.yaml create mode 100644 examples/docs/scheduled-review/workflow.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a601ae2..005c75f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,6 +55,9 @@ jobs: - name: Run deterministic verification gate run: cargo xtask verify + - name: Verify canonical documentation and examples + run: cargo xtask docs-verify + - name: Run credential-free acceptance gate run: cargo xtask acceptance diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..7a02d82 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,17 @@ +# Code of conduct + +## Our standard + +Contributors and maintainers must keep project spaces respectful, professional, and focused on the work. Welcome questions asked in good faith. Give specific technical feedback without personal attacks. Respect privacy, identity, background, experience level, and accessibility needs. + +Unacceptable behavior includes harassment, discrimination, threats, sexualized attention, doxxing, deliberate intimidation, sustained disruption, or publishing another person's private information without permission. + +## Scope + +This standard applies in repository discussions, reviews, issues, project chat, events, and public representation of the project. + +## Reporting + +Report conduct concerns privately to the repository owners through a private channel available on their GitHub organization profile. Do not use a public issue when disclosure could harm someone. Project owners will review available evidence, limit distribution, and choose a proportionate response. This document does not promise a response deadline. + +For security vulnerabilities, follow [SECURITY.md](SECURITY.md) instead. diff --git a/README.md b/README.md index cb2206b..377807b 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ CI uses the scripted fake provider. Native, mock-tested adapters cover OpenAI Re - `crates/agentctl-cli`: production CLI - `xtask`: generated artifacts and canonical verification -Start with [Product](docs/PRODUCT.md), [Architecture](docs/ARCHITECTURE.md), [DSL](docs/DSL.md), [Operations](docs/OPERATIONS.md), [Container contract](docs/CONTAINER.md), [Release process](docs/RELEASE_PROCESS.md), [Limitations](docs/LIMITATIONS.md), [Security](docs/SECURITY.md), and the [generated CLI reference](docs/generated/CLI.md). Run the release-readiness layers with: +Start with [Getting started](docs/guides/GETTING_STARTED.md), [Product](docs/PRODUCT.md), [Architecture](docs/ARCHITECTURE.md), [DSL](docs/DSL.md), [Operations](docs/OPERATIONS.md), [Container contract](docs/CONTAINER.md), [Troubleshooting](docs/guides/TROUBLESHOOTING.md), [Contributing](docs/CONTRIBUTING.md), [Limitations](docs/LIMITATIONS.md), [Security](docs/SECURITY.md), and the [generated CLI reference](docs/generated/CLI.md). Run the release-readiness layers with: ```console cargo xtask verify diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..9824701 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,17 @@ +# Security policy + +## Supported line + +The current supported development line is the `agentctl.dev/v1alpha1` release-candidate source on the default branch. There is no stable v1 release or long-term support promise yet. + +## Report a vulnerability privately + +Use GitHub's private vulnerability reporting flow for `opensourceops/agentctl` when it is enabled. Do not open a public issue with exploit details. If the private form is unavailable, contact the repository owners through a private channel listed on the OpenSourceOps GitHub organization profile before sending sensitive details. + +Include the affected commit or version, impact, minimal reproduction, and suggested mitigation. Remove credentials, production prompts, database contents, and confidential artifacts. Use clearly fake values in every reproduction. + +The maintainers do not promise a response or remediation deadline. They will assess reports against the implemented trust boundary and coordinate disclosure when appropriate. + +## Public hardening questions + +Questions about documented boundaries that do not disclose a vulnerability may use a GitHub discussion or issue. Read [Security](docs/SECURITY.md), [Threat model](docs/THREAT_MODEL.md), and [Limitations](docs/LIMITATIONS.md) first. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 8ec414f..59c3c25 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -33,4 +33,4 @@ The workspace uses Rust edition 2024, pins Rust 1.88 as the MSRV, forbids unsafe The OCI build is multi-stage: only the optimized Rust binary enters a maintained distroless runtime with CA roots and a non-root identity. `/config` is workflow configuration, `/workspace` is the read-only working tree, `/state` holds SQLite, and `/artifacts` receives declared outputs. State must be mounted again for inspect/resume/replay. The root filesystem may be read-only. See [Container contract](CONTAINER.md) and ADR 0007. -See the [ADRs](adr/) for the decisions and [Durable execution](DURABLE_EXECUTION.md) for failure semantics. +See the [architecture diagrams](architecture/DIAGRAMS.md), [ADRs](adr/), and [Durable execution](DURABLE_EXECUTION.md) for failure semantics. diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index ea83d81..8550601 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,15 +1,79 @@ # Contributing -Use the pinned Rust toolchain and keep changes scoped to the deterministic product. Before editing a public contract, add or update a fixture/test and an ADR when durability, security, compatibility, dependency direction, or protocol version changes. +Thank you for improving `agentctl`. Keep changes narrow, add executable evidence for public behavior, and preserve the deterministic and security boundaries. -```console -cargo fmt --all +## Before you start + +Read the [code of conduct](../CODE_OF_CONDUCT.md), [product definition](PRODUCT.md), [architecture](ARCHITECTURE.md), [security model](SECURITY.md), and [limitations](LIMITATIONS.md). Search existing issues before proposing new work. Use an issue to discuss large compatibility, protocol, persistence, or security changes before implementation. + +Do not use a public issue for a vulnerability. Follow the private process in [SECURITY.md](../SECURITY.md). + +## Choose work + +Prefer a scoped issue with expected behavior. For a bug, add a failing test that reproduces the user-visible problem before the fix. For a feature, define validation, policy, persistence, recovery, compatibility, and documentation effects. + +The maintainers do not promise response or review times. + +## Set up development + +Install the pinned Rust 1.88 toolchain with Rustfmt and Clippy. From the repository root: + +```text +cargo build --workspace --locked +cargo test --workspace --all-features --locked +cargo xtask docs-verify +``` + +Normal tests need no provider credential. Install the pinned `cargo-deny` version documented in `.github/workflows/ci.yml` before running the complete verification gate. + +## Branches and commits + +Create a focused feature branch. Keep unrelated formatting, renames, and refactors out of the change. Write commits that explain one coherent behavior or documentation change. Generated schema and CLI reference changes belong with the source change that caused them. + +Do not commit runtime databases, build output, provider responses, API keys, local absolute paths, or private release evidence. + +## Build and test + +Before requesting review: + +```text +cargo fmt --all -- --check cargo clippy --workspace --all-targets --all-features -- -D warnings cargo test --workspace --all-features --locked cargo xtask generate +cargo xtask docs-verify cargo xtask verify +cargo xtask acceptance +git diff --check ``` -Generated schema and CLI reference must be committed. No test, example, benchmark, fuzz target, or CI job may require provider credentials. Do not add raw keys, secret CLI flags, redirects, shell-string execution, unbounded retries/turns, or implicit effects. New providers require native mapping, capabilities, normalized errors/usage/cancellation, documentation, example configuration, and mock conformance. New tools require both schemas, risk/effect/idempotency/approval metadata, policy hooks, and malicious-output tests. +Run `cargo xtask acceptance-container` when a container, Containerfile, mount contract, signal path, filesystem behavior, or packaging boundary changes. Live OpenAI acceptance is an explicit credentialed release gate, not a normal contribution requirement. + +## Special changes + +- Actions and tools: follow [Add an action or tool](development/ADD_ACTION.md). +- Providers: follow [Add a provider](development/ADD_PROVIDER.md). +- MCP or A2A: add pinned-protocol mock coverage, timeouts, cancellation, policy, redaction, and ambiguous-delivery behavior. +- Store migrations: follow [Add a store migration](development/ADD_MIGRATION.md). +- Workflow or durable compatibility: update fixtures, generated schema, public policy, and an ADR when the decision is architectural. +- Documentation and examples: follow [Write and verify documentation](development/DOCUMENTATION.md). + +## Pull request checklist + +- The change is linked to a clear problem. +- Tests fail before the fix where practical and pass after it. +- Security, policy, effect, recovery, and redaction behavior is explicit. +- No live credential is needed by normal CI. +- Generated files are current. +- Public examples are executable and use fake providers or local mocks by default. +- Compatibility and limitations are updated. +- New public writing contains no em dash and uses precise maturity language. +- The diff contains no unrelated cleanup. + +## Review expectations + +Reviewers focus on correctness, deterministic behavior, explicit effects, safe failure, compatibility, tests, and truthful documentation. Address each review comment with a change or a concrete technical explanation. A local pass does not replace hosted evidence for an RC. + +## Release process -Dependencies must be registry releases with reviewed licenses and no wildcard constraints. Unsafe Rust is forbidden. Cross-platform behavior belongs in the CI matrix. Update `docs/execution` with exact evidence when finishing a release gate. +Maintainers follow [Release process](RELEASE_PROCESS.md). Candidate promotion requires the exact remote commit to pass required hosted checks and artifact verification. Contributors must not create tags, publish packages, or describe a local build as released. diff --git a/docs/OBSERVABILITY.md b/docs/OBSERVABILITY.md index 2e07351..689f193 100644 --- a/docs/OBSERVABILITY.md +++ b/docs/OBSERVABILITY.md @@ -1,9 +1,46 @@ # Observability -The runtime emits versioned typed events for runs, tasks, attempts, agent turns, provider/model responses, tool/effect calls, approvals, MCP/A2A operations, retries, checkpoints, state transitions, and useful database boundaries. Events carry run/task/effect and trace correlation plus phase and timestamp. +Observability has two audiences: terminal users need a concise final result, while operators need durable evidence for diagnosis and audit. The runtime keeps those contracts separate. + +## CLI streams + +Human output is the default for interactive use. For automation, use one versioned JSON document: + +```bash +agentctl run workflow.yaml --db .agentctl/runtime.db --output json --color never +``` + +Success writes an `agentctl.dev/cli/v1` envelope to stdout. Failure writes the same envelope shape to stderr and returns a typed exit code. Run-scoped results include run and trace IDs. JSONL progress streaming is not implemented in this release; do not parse human output or assume that each line is an event. + +## Durable inspection + +The SQLite database is the authoritative local record. Inspect a run and database without invoking a provider or repeating an effect: + +```bash +agentctl inspect RUN_ID --db .agentctl/runtime.db --output json --color never +agentctl db stats --db .agentctl/runtime.db --output json --color never +``` + +Inspection includes task attempts, checkpoints, effect state, approvals, provider and protocol records, ordered audit events, and trace correlation. Use `agentctl approvals list RUN_ID` when the run exited pending approval. Preserve the database and its WAL files together when the history is operational evidence. + +## Runtime events + +The runtime emits versioned typed events for runs, tasks, attempts, agent turns, provider/model responses, tool/effect calls, approvals, MCP/A2A operations, retries, checkpoints, state transitions, and useful database boundaries. Events carry run, task, effect, and trace correlation plus phase and timestamp. `agentctl-observability` provides a no-op sink, buffered test sink, and an OpenTelemetry-compatible global tracer bridge. Tracing is optional and has no role in scheduling or replay. Structured audit events are persisted separately in SQLite and ordered per run. +OpenTelemetry export is an embedding concern in this release; the standalone CLI does not expose an exporter configuration flag. An application using the runtime can install the bridge and route spans through its own collector configuration. A tracing outage must not alter workflow scheduling or replay semantics. + +## Metrics and interpretation + +Usage maps input, output, reasoning, cache-read, and cache-write tokens where providers expose them. Duration, attempts, provider errors, retries, approval waits, tool counts, and action change status are available from trace and audit events. Price calculation is not fabricated when no reliable price metadata exists. + +When diagnosing a failure, correlate the final envelope's run and trace IDs with the persisted task, attempt, effect, and provider records. A model response is not proof that an external effect completed; use the effect record and its confirmation state. + +## Sensitive data + Sensitive field names and registered secret values are redacted before trace attributes leave the runtime. Provider response content is not printed by the live smoke. Operators must still treat trace backends and the local database as sensitive because prompts, file content, tool output, and remote artifacts may contain confidential non-secret data. -Usage maps input/output/reasoning/cache-read/cache-write tokens where providers expose them. Duration, attempts, provider errors, retries, approval waits, tool counts, and action change status are available from trace and audit events. Price calculation is not fabricated when no reliable price metadata exists. +Keep provider credentials in environment references, never workflow inputs or command arguments. Apply access control and retention to the database, collected artifacts, CI logs, and trace backend. Before sharing diagnostics, remove credentials, prompt content, file content, remote payloads, and identifying metadata; a run ID alone is sufficient for local correlation. + +See [CLI output and exit codes](reference/CLI_OUTPUT.md), [local operation](guides/LOCAL_OPERATION.md), and [runtime database and migrations](reference/DATABASE.md) for the complete operating contract. diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md index 40db127..0bf0890 100644 --- a/docs/OPERATIONS.md +++ b/docs/OPERATIONS.md @@ -15,7 +15,7 @@ Scheduling belongs to the external platform. `agentctl` owns deterministic execu Use absolute paths and an external overlap lock when two schedules must not affect the same resource: -```cron +```text */15 * * * * /usr/bin/flock -n /var/lib/agentctl/report.lock /usr/local/bin/agentctl run /etc/agentctl/report.yaml --workspace /srv/app --db /var/lib/agentctl/runtime.db --inputs-file /etc/agentctl/inputs.json --timeout-seconds 600 --output json --color never >>/var/log/agentctl/report.jsonl 2>>/var/log/agentctl/report.err ``` diff --git a/docs/architecture/DIAGRAMS.md b/docs/architecture/DIAGRAMS.md new file mode 100644 index 0000000..8f2e94e --- /dev/null +++ b/docs/architecture/DIAGRAMS.md @@ -0,0 +1,290 @@ +# Architecture diagrams + +These diagrams explain implemented `v1alpha1` behavior. Each diagram is paired with text so the relationship is available when Mermaid cannot render. + +## High-level system architecture + +The CLI composes deterministic core contracts with persistence, runtime execution, concrete providers, protocols, and optional tracing. + +```mermaid +flowchart LR + accTitle: High-level agentctl system architecture + accDescr: A workflow author uses the CLI, which joins deterministic core contracts to runtime providers, protocols, executors, tracing, and SQLite. + User[Workflow author or operator] --> CLI[agentctl CLI] + CLI --> Core[Core parser compiler policy state] + CLI --> Runtime[Sequential runtime] + Runtime --> Store[SQLite store] + Runtime --> Providers[Native model providers] + Runtime --> Protocols[MCP and A2A clients] + Runtime --> Executors[Files processes and built-in tools] + Runtime --> Traces[Audit events and optional OpenTelemetry] + Core --> Runtime +``` + +The core owns the graph and rules. Concrete I/O stays at the runtime boundary. SQLite is local durable state, not a distributed service. + +## Workflow compilation + +Compilation turns one strict document into a versioned deterministic plan before execution begins. + +```mermaid +flowchart LR + accTitle: Workflow compilation stages + accDescr: Versioned YAML passes through strict parsing, validation, graph construction, and digest calculation to become a compiled plan. + Source[Versioned YAML] --> Parse[Strict parse and migration diagnostics] + Parse --> Validate[References templates policy and capabilities] + Validate --> Graph[Cycle check and declaration-order DAG] + Graph --> Digest[Canonical workflow and plan digests] + Digest --> Plan[Compiled plan] +``` + +Unknown fields, cycles, missing references, invalid templates, and unsupported provider capabilities fail before a run performs effects. + +## Run lifecycle + +A normal run moves through durable states and ends in one terminal result or a durable pause. + +```mermaid +flowchart TD + accTitle: Run lifecycle + accDescr: A run creates durable records, executes ready tasks, persists results, and reaches success, approval, failure, or cancellation. + Create[Create run and task records] --> Ready[Find next ready task] + Ready --> Execute[Execute action or bounded agent] + Execute --> Persist[Commit task output checkpoint and audit] + Persist --> More{More ready tasks?} + More -->|Yes| Ready + More -->|No| Success[Succeeded] + Execute --> Approval[Pending approval] + Execute --> Failure[Failed or cancelled] +``` + +The current scheduler runs one ready task at a time in declaration order. A pending approval is non-terminal and can later resume. + +## Runtime state machine + +Run and task transitions are validated instead of being inferred from missing records. + +```mermaid +stateDiagram-v2 + accTitle: Runtime state machine + accDescr: Pending runs become running, can wait for approval, and terminate as succeeded, failed, or cancelled. + [*] --> Pending + Pending --> Running + Running --> WaitingApproval + WaitingApproval --> Running: approval resolved and resume + Running --> Succeeded + Running --> Failed + Running --> Cancelled + Pending --> Cancelled + Succeeded --> [*] + Failed --> [*] + Cancelled --> [*] +``` + +Invalid transitions fail explicitly. Replay requires a terminal source; resume requires a safe non-terminal source. + +## Effect recording + +Every non-pure operation is requested durably before an executor starts. + +```mermaid +sequenceDiagram + accTitle: Effect recording sequence + accDescr: The runtime records an effect before dispatch and then persists either its confirmed result or an uncertain state. + participant R as Runtime + participant S as SQLite store + participant E as Effect executor + R->>S: Persist requested effect and stable identity + R->>S: Mark effect started + R->>E: Dispatch bounded operation + alt confirmed result + E-->>R: Result + R->>S: Commit confirmed result and task evidence + else dispatch outcome ambiguous + R->>S: Mark effect uncertain + end +``` + +A request-before-start ledger supports reuse of confirmed results. It does not prove exactly-once behavior in an external system. + +## Resume flow + +Resume continues the same non-terminal run only when durable evidence makes continuation safe. + +```mermaid +flowchart TD + accTitle: Resume flow + accDescr: Resume loads the same run, stops for uncertain effects, reuses confirmed results, and continues safe pending work. + Load[Load same run and checkpoint] --> Scan[Inspect tasks approvals and effects] + Scan --> Uncertain{Started unconfirmed effect?} + Uncertain -->|Yes| Stop[Stop for operator reconciliation] + Uncertain -->|No| Confirmed{Confirmed prior effect?} + Confirmed -->|Yes| Reuse[Reuse recorded result] + Confirmed -->|No| Continue[Execute next requested work] + Reuse --> Continue +``` + +Resume preserves the run identity and progress. It never silently repeats an uncertain external effect. + +## Recorded replay flow + +Recorded replay constructs a new linked record entirely from terminal stored evidence. + +```mermaid +flowchart LR + accTitle: Recorded replay flow + accDescr: Replay copies terminal stored evidence into a linked replay run without calling providers, tools, files, processes, or networks. + Terminal[Terminal source run] --> Validate[Validate all source tasks are terminal] + Validate --> Copy[Copy recorded task outputs effects and tool calls] + Copy --> Replay[Create replay-mode run linked to source] + Replay --> Result[Return recorded outcome] + Executors[Provider tool file process and network executors] -. not called .-> Replay +``` + +Replay reports historical truth. It does not observe current files, rerun verification, or contact a provider. + +## Fork or rerun flow + +Fork makes fresh execution an explicit choice instead of overloading replay. + +```mermaid +flowchart LR + accTitle: Fork or rerun flow + accDescr: Fork loads a prior declaration into a child run, resets working memory, and executes fresh effects for an independent outcome. + Source[Prior run] --> Load[Load source workflow plan and inputs] + Load --> Child[Create child run with parent link] + Child --> Reset[Use declared initial working memory] + Reset --> Execute[Execute tasks with fresh effects] + Execute --> Outcome[Independent outcome] +``` + +Fork may repeat external mutations and may produce a different result. Reconcile uncertain source effects before forking. + +## Approval lifecycle + +Policy can stop an effect before dispatch and require an operator-controlled decision. + +```mermaid +sequenceDiagram + accTitle: Approval lifecycle + accDescr: Policy requires approval, the runtime persists and reports it, an operator resolves it, and the same run resumes. + participant R as Runtime + participant P as Policy engine + participant S as SQLite store + participant O as Operator + R->>P: Evaluate capability resource and risk + P-->>R: Approval required + R->>S: Persist redacted approval request + R-->>O: Exit 3 with run and trace IDs + O->>S: Approve or reject with actor and reason + O->>R: Resume same run + R->>S: Read resolution and continue or fail +``` + +Non-interactive execution never waits on stdin or auto-approves. The platform authenticates the operator. + +## Container deployment + +The production image is a non-root CLI with four explicit host-managed mounts. + +```mermaid +flowchart LR + accTitle: Container deployment contract + accDescr: A non-root agentctl container reads config and workspace mounts, writes state and artifacts, receives secret references, and returns JSON and an exit code. + Config[Read-only /config] --> Container[Distroless agentctl UID 65532] + Workspace[Usually read-only /workspace] --> Container + Container --> State[Writable /state SQLite] + Container --> Artifacts[Writable /artifacts] + Secrets[Environment secret references] --> Container + Container --> Output[One JSON result and process exit code] +``` + +The root filesystem can remain read-only. State must persist for inspection, approval, resume, and replay. + +## CI/CD execution + +CI remains the outer scheduler and artifact system. + +```mermaid +flowchart TD + accTitle: CI and CD execution + accDescr: CI prepares mounts, runs the generic container step, interprets JSON and exit status, collects evidence, and handles approval through an operator job. + Checkout[CI checks out workflow and source] --> Prepare[Prepare config state workspace and artifacts] + Prepare --> Run[Run generic agentctl OCI step] + Run --> Code[Interpret stable exit code] + Run --> Json[Parse final JSON envelope] + Run --> Collect[Collect protected state and declared artifacts] + Code --> Approval{Exit 3?} + Approval -->|Yes| Operator[Operator-controlled resolution job] + Operator --> Resume[Resume with retained state] +``` + +GitHub Actions, GitLab CI, Jenkins, Harness CI, and Kubernetes use the same mount and process contract. + +## Provider and tool interaction + +The runtime, not the model, owns tool visibility, policy, validation, and effect recording. + +```mermaid +sequenceDiagram + accTitle: Provider and tool interaction + accDescr: The runtime maps neutral messages through a native provider, validates model tool calls, authorizes execution, and returns correlated results. + participant R as Runtime agent loop + participant P as Native provider + participant M as Model + participant T as Tool executor + R->>P: Provider-neutral messages and strict tools + P->>M: Native request + M-->>P: Tool call or final content + P-->>R: Neutral response and continuation + R->>R: Validate schema policy approval and limits + R->>T: Execute authorized tool with effect identity + T-->>R: Validated output + R->>P: Correlated tool result and continuation +``` + +Provider-native types stop at the adapter. Model output cannot change policy or tool metadata. + +## MCP and A2A boundaries + +Both protocols are remote effects with pinned versions, explicit hosts, environment-backed headers, and conservative ambiguity handling. + +```mermaid +flowchart LR + accTitle: MCP and A2A boundaries + accDescr: Runtime policy and the effect ledger mediate communication with untrusted remote MCP tool servers and A2A agents. + Workflow[Compiled workflow] --> Runtime[Runtime policy and effect ledger] + Runtime --> MCP[MCP 2025-11-25 Streamable HTTP] + Runtime --> A2A[A2A 1.0 Agent Card and JSON-RPC] + MCP --> McpPeer[Untrusted remote tool server] + A2A --> A2aPeer[Untrusted remote agent] + McpPeer --> Runtime + A2aPeer --> Runtime +``` + +MCP annotations and A2A cards are untrusted metadata. The clients do not automatically reconnect or resubmit after an ambiguous operation. + +## Crate dependency map + +The dependency direction keeps deterministic contracts independent from adapters. + +```mermaid +flowchart TD + accTitle: Crate dependency map + accDescr: CLI, runtime, provider, protocol, store, observability, and xtask crates depend inward on deterministic core contracts. + CLI[agentctl-cli] --> Runtime[agentctl-runtime] + CLI --> Providers[agentctl-providers] + CLI --> Protocols[agentctl-protocols] + CLI --> Store[agentctl-store] + Runtime --> Core[agentctl-core] + Runtime --> Store + Runtime --> Observability[agentctl-observability] + Providers --> Core + Protocols --> Core + Protocols --> Runtime + Store --> Core + Observability --> Core + Xtask[xtask] --> CLI +``` + +`agentctl-core` has no dependency on HTTP, SQLite, CLI parsing, or concrete executor types. `xtask` drives the built CLI for generation and acceptance. diff --git a/docs/development/ADD_ACTION.md b/docs/development/ADD_ACTION.md new file mode 100644 index 0000000..57d2496 --- /dev/null +++ b/docs/development/ADD_ACTION.md @@ -0,0 +1,41 @@ +# Add an action or tool + +An action is selected directly by a task. A tool is requested by a model. Both need explicit data, policy, effect, persistence, replay, and test contracts. + +## 1. Define the contract + +Add the DSL kind and strict fields in `agentctl-core`. Deny unknown fields. Define the input and output shape, size and timeout bounds, and diagnostics for invalid configuration. + +For a model-callable tool, require strict JSON Schema with `additionalProperties: false` where appropriate. Add capability, risk, effect class, idempotency, retry-safety, approval, secret, and network metadata. + +## 2. Classify the effect + +Choose the narrowest honest class. Pure computation needs no external guarantee. Reads are observations, writes are mutations, processes are process execution, and remote agents are separate from ordinary network calls. + +State whether the operation is pure, idempotent, keyed, at-most-once, or unknown. Do not mark an operation retry-safe merely because retry is convenient. + +## 3. Enforce policy outside the executor + +Add the capability and resource checks before dispatch. A tool declaration cannot weaken global policy. Model output and remote metadata cannot grant authority. + +## 4. Persist request and result + +Create the effect record before invoking the implementation. Store a bounded, redacted request, stable digest, effect ID, status, confirmation, result or error, and trace correlation. Decide how a crash after dispatch becomes uncertain. + +## 5. Define replay behavior + +Recorded replay must use stored terminal output and call no new executor. Resume may reuse a confirmed result. Fork may perform a fresh operation. Add a regression test that panics if replay reaches the executor. + +## 6. Test the boundary + +Test valid input, invalid configuration, schema rejection, policy denial, approval, timeout, cancellation, output limits, redaction, persistence failure, uncertain dispatch, resume reuse, replay, and fork. Add a clean credential-free example when users need the feature. + +## 7. Document the contract + +Update the DSL, tool matrix, security boundary, architecture, limitations, generated schema, and site manifest as needed. Run: + +```text +cargo xtask generate +cargo xtask docs-verify +cargo xtask verify +``` diff --git a/docs/development/ADD_MIGRATION.md b/docs/development/ADD_MIGRATION.md new file mode 100644 index 0000000..c2929ab --- /dev/null +++ b/docs/development/ADD_MIGRATION.md @@ -0,0 +1,23 @@ +# Add a store migration + +The SQLite schema is versioned with `PRAGMA user_version`. Migrations are forward-only and run in order. + +## 1. Define the compatibility change + +State which persisted versions can upgrade, which runtime/checkpoint/effect formats change, and how older binaries fail. Never silently ignore a future version. + +## 2. Add one migration + +Increment `DATABASE_SCHEMA_VERSION`, add the next migration string in `agentctl-store`, and include it in the ordered list. Use SQLite operations supported by the bundled library. Keep the migration transactional. + +## 3. Preserve failure behavior + +A failed migration must leave the prior database usable or fail clearly without partial success. Serialization, checksum, foreign-key, and incompatible-state errors remain explicit. + +## 4. Test forward paths + +Create the previous schema in a temporary database, insert representative durable state, open it with the new store, and assert the new version and records. Test an already-current database, an empty database, a future version, corrupt state, and an intentional migration failure. + +## 5. Document operator impact + +Update the database reference, compatibility policy, release notes or status evidence, and backup guidance. Explain whether downgrade remains possible. Run the complete store tests and `cargo xtask verify`. diff --git a/docs/development/ADD_PROVIDER.md b/docs/development/ADD_PROVIDER.md new file mode 100644 index 0000000..97924fd --- /dev/null +++ b/docs/development/ADD_PROVIDER.md @@ -0,0 +1,35 @@ +# Add a provider + +Provider support means a native adapter with explicit capabilities and deterministic protocol evidence. A provider name alone is not support. + +## Capability metadata + +Declare support for text, structured output, tools, reasoning, continuation, cache options, usage fields, and limits. The compiler must reject any requested feature the adapter cannot honor. + +## Authentication and network boundary + +Use a workflow environment reference. Resolve credentials only at the adapter boundary, never from a CLI key flag. Enforce the reviewed endpoint host, disable redirects, use rustls, and define whether an endpoint override is permitted. + +## Native request mapping + +Map provider-neutral messages, tool definitions, tool results, structured output, reasoning, and continuation into the provider's native API. Do not route a native API through an assumed OpenAI-compatible shape. + +## Response and usage mapping + +Parse every supported content block, tool call ID, finish reason, continuation token, request ID, and usage counter. Validate untrusted JSON and bound response reads. Do not invent monetary cost when the provider does not return authoritative cost data. + +## Timeouts, cancellation, and errors + +Normalize status, authentication, rate limit, malformed response, timeout, cancellation, and transport errors. Retry only definitive retryable responses within the task bound. Treat loss after dispatch as ambiguous when the provider may have acted. + +## Tool continuation + +Preserve correlation across model response, tool call, durable effect, tool result, and the next provider request. Document whether continuation depends on stored provider responses or stateless replayed items. + +## Evidence + +Add local mock-protocol tests for request mapping, authentication, headers, redirects, errors, usage, tool continuation, cancellation, redaction, and response bounds. Add provider conformance fixtures without credentials. Live validation must be an opt-in bounded gate with retained sanitized evidence and must never become a normal CI requirement. + +## Documentation claims + +Update the provider guide and matrix with the exact level: implemented, mock-protocol tested, retained live evidence, or deferred. Add an example that passes `check` without resolving a secret. Run `cargo xtask generate`, `cargo xtask docs-verify`, and `cargo xtask verify`. diff --git a/docs/development/DOCUMENTATION.md b/docs/development/DOCUMENTATION.md new file mode 100644 index 0000000..22fe83b --- /dev/null +++ b/docs/development/DOCUMENTATION.md @@ -0,0 +1,41 @@ +# Write and verify documentation + +## Ownership + +The `agentctl` repository owns commands, schema, examples, runtime behavior, provider and protocol capability, security, architecture, limitations, and contributor contracts. The `opensourceops.github.io` repository owns the public homepage, navigation, learning paths, search, styling, metadata, browser tests, and Pages deployment. + +Do not hand-copy a prominent YAML example into the site repository. Add or update a checked example here and include it through the Pages import mechanism. + +## Add an example + +Place public journeys in `examples/docs/` with a README entry, provider classification, expected result, verification command, network requirement, and security note. Use fake providers or local mocks for normal verification. Name live examples clearly and keep them opt-in. + +## Write public content + +- Use sentence-case headings, active voice, short paragraphs, and descriptive links. +- State the working directory, writes, credentials, and network effect for commands. +- Use exact commands and complete valid YAML. +- Distinguish implemented, deterministic, mock-tested, live evidence, hosted configuration, hosted execution, and deferred work. +- Never use an em dash in public copy. +- Avoid hype, generic AI claims, and unsupported maturity language. +- Explain every Mermaid diagram before and after it. + +## Verify locally + +From this repository: + +```text +cargo xtask docs-verify +``` + +From the Pages repository: + +```text +AGENTCTL_REPO=/path/to/agentctl pnpm verify:agentctl +``` + +The site command imports canonical content, records the source commit, validates writing and links, checks Mermaid, builds search, assembles the physical `/agentctl/` artifact, then runs browser and accessibility tests. + +## Review + +Review technical claims against source, generated help, schema, tests, and evidence. Check keyboard navigation, heading order, link purpose, alt text, diagram explanations, mobile code blocks, and direct deep links. Do not claim accessibility certification from automated tooling alone. diff --git a/docs/development/REPOSITORY.md b/docs/development/REPOSITORY.md new file mode 100644 index 0000000..4504979 --- /dev/null +++ b/docs/development/REPOSITORY.md @@ -0,0 +1,63 @@ +# Developer guide + +## Repository layout + +The production implementation is a Rust workspace. The remaining top-level TypeScript source is an archived compatibility reference and has no production package entrypoint. + +| Crate | Responsibility | +| --- | --- | +| `agentctl-core` | strict DSL, migration, compiler, templates, state, effects, policy, provider and tool contracts | +| `agentctl-store` | versioned SQLite persistence, migrations, checkpoints, approvals, audit, trace, sessions, tool calls, memory | +| `agentctl-runtime` | sequential scheduler, actions, bounded agent loop, resume, replay, fork, cancellation | +| `agentctl-providers` | native OpenAI, Azure OpenAI, Anthropic, Google, and fake adapters | +| `agentctl-protocols` | MCP and A2A clients | +| `agentctl-observability` | typed events, test sink, and OpenTelemetry bridge | +| `agentctl-cli` | command parsing, filesystem and process boundary, adapters, output envelopes, exit codes | +| `xtask` | generation, verification, acceptance, container, packaging, and secret checks | + +Dependency direction keeps the core free of HTTP, SQLite, CLI, and concrete clock or ID implementations. Concrete effects stay at runtime edges and receive stable effect identity. + +## Development setup + +Install the pinned Rust 1.88 toolchain with Rustfmt and Clippy, then from the repository root: + +```text +cargo build --workspace --locked +cargo test --workspace --all-features --locked +cargo xtask docs-verify +``` + +Normal development and documentation tests use no provider credential. Install `cargo-deny` 0.20.2 before the complete `cargo xtask verify` gate. + +## Deterministic core and effect boundaries + +Parsing and compilation must be pure for the same source and inputs. The compiler resolves references, validates capabilities, orders the DAG, and computes a plan digest. The runtime calls injected implementations for clocks, IDs, files, processes, providers, tools, protocols, state, and traces. + +An operation that observes or changes non-pure state needs an effect classification and a request record before dispatch. A completed confirmed result can be reused. An unconfirmed started result is uncertain. Do not add automatic retry around ambiguous transport or process failures. + +## Runtime state machine + +Run and task transitions use enums in `agentctl-core`; the store validates transitions and couples important updates in SQLite transactions. Working-memory replacement, task transition, checkpoint, and audit event commit together. Tool effect and tool-call terminal states also commit together. + +Resume continues the same run. Recorded replay creates a linked no-effect record from a terminal source. Fork creates a child run with fresh execution. Any change that alters these semantics needs tests, compatibility notes, and an ADR. + +## Providers, tools, MCP, and A2A + +Provider adapters implement the neutral model contract and publish typed capabilities. Tools publish strict schemas plus security and recovery metadata. MCP pins `2025-11-25`; A2A pins `1.0`. New protocol behavior needs deterministic local mock peers, bounded timeouts, cancellation, native error mapping, and explicit ambiguous-delivery behavior. + +## Testing strategy + +- Unit tests cover local invariants and negative contracts. +- Integration tests cover compiler, store, runtime, provider, protocol, policy, and trace boundaries. +- Compatibility fixtures preserve selected language-neutral behavior. +- Property tests cover templates and typed preservation. +- Fuzz targets cover YAML, provider and protocol responses, persisted state, and tool schema input. +- Acceptance tests run clean-directory and packaged user journeys. +- Container acceptance checks the non-root, read-only, state, artifact, signal, and offline replay contract. +- Live OpenAI acceptance is explicit, bounded, credentialed, and never part of normal CI. + +## Documentation and release changes + +Run `cargo xtask generate` whenever CLI help or the DSL changes. Run `cargo xtask docs-verify` for public content and examples. Update the Pages site's content manifest when adding a new canonical public page. Release decisions depend on hosted evidence for the exact candidate commit; local success alone does not approve an RC. + +Related guides: [Add an action](ADD_ACTION.md), [Add a provider](ADD_PROVIDER.md), [Add a store migration](ADD_MIGRATION.md), [Write documentation](DOCUMENTATION.md), [Testing](../TESTING.md), and [Release process](../RELEASE_PROCESS.md). diff --git a/docs/guides/CI_CD.md b/docs/guides/CI_CD.md new file mode 100644 index 0000000..25bdb53 --- /dev/null +++ b/docs/guides/CI_CD.md @@ -0,0 +1,66 @@ +# Integrate agentctl into CI/CD + +`agentctl` is one OCI step inside the pipeline. The CI system checks out code, injects secrets, schedules work, retains state, and collects artifacts. `agentctl` validates and executes one bounded workflow with durable local history. + +## Shared container contract + +Every platform uses the same paths: + +| Mount | Access | Purpose | +| --- | --- | --- | +| `/config` | read-only | reviewed workflow, inputs, and packs | +| `/workspace` | normally read-only | checked-out source and fixtures | +| `/state` | writable and retained | SQLite database, resume, replay, approvals | +| `/artifacts` | writable and collected | declared reports and outputs | + +Use `--output json --color never`. A successful workflow exits `0`. Validation exits `2`; policy or a pending approval exits `3`; run failure exits `4`; persistence exits `5`; provider or protocol failure exits `6`; cancellation exits `130`. + +## Generic step + +From a CI workspace that contains `config/workflow.yaml`: + +```text +mkdir -p .agentctl-state artifacts +docker run --rm --read-only --user 65532:65532 \ + --tmpfs /tmp:rw,noexec,nosuid,size=16m \ + --mount type=bind,src="$PWD/config",dst=/config,readonly \ + --mount type=bind,src="$PWD",dst=/workspace,readonly \ + --mount type=bind,src="$PWD/.agentctl-state",dst=/state \ + --mount type=bind,src="$PWD/artifacts",dst=/artifacts \ + ghcr.io/OWNER/agentctl:0.2.0 \ + run /config/workflow.yaml --workspace /workspace \ + --db /state/runtime.db --output json --color never +``` + +Replace the image owner and tag with a reviewed image. The repository does not claim that this example image exists publicly. + +## Platform guides + +The [container contract](../CONTAINER.md) contains complete examples for GitHub Actions, GitLab CI, Jenkins, Harness CI, Kubernetes Job, and Kubernetes CronJob. Each example preserves the same entrypoint, mounts, outputs, secrets, and exit behavior. + +Their current evidence level is documentation or syntax review unless stated otherwise. The local container acceptance validates the generic contract, not every hosted platform. + +## Inputs and structured output + +Mount an ordinary JSON file under `/config` and pass `--inputs-file /config/inputs.json`, or use repeated non-secret `--input KEY=VALUE`. Provider credentials must be environment references. Capture stdout as one `agentctl.dev/cli/v1` JSON envelope and archive declared files from `/artifacts`. + +## Approvals in pipelines + +A non-interactive approval does not wait for stdin. It persists a request, exits `3`, and requires the same `/state` data in a later operator-controlled job. That job lists and resolves the approval, then calls `resume`. If your pipeline cannot retain protected state between jobs, configure policy to deny or fail instead of using approvals. + +## Retention and recovery + +Collect `/state` even on failure when recovery or audit matters. It can contain confidential prompts and outputs, so apply protected artifact access and a short, documented retention period. Keep `/artifacts` according to the report's classification. + +Do not set a pipeline retry policy that blindly repeats exit `5`, `6`, or `130`. Inspect the run first, because an external effect may be uncertain. + +## Security checklist + +- Pin the workflow and image version. +- Run as non-root with a read-only root filesystem. +- Drop capabilities and deny unneeded egress. +- Mount the workspace read-only unless a reviewed write is required. +- Inject secrets by environment reference and never echo them. +- Treat remote content and model output as untrusted. +- Retain state for approval or recovery, then delete it under policy. +- Set the external platform's overlap and timeout controls. diff --git a/docs/guides/FIRST_AGENT_WORKFLOW.md b/docs/guides/FIRST_AGENT_WORKFLOW.md new file mode 100644 index 0000000..fafb777 --- /dev/null +++ b/docs/guides/FIRST_AGENT_WORKFLOW.md @@ -0,0 +1,83 @@ +# Run your first bounded agent workflow + +You will run a tool-using agent with the deterministic fake provider. The model path is scripted, but the workflow exercises the real compiler, agent loop, tool policy, tool schemas, effect ledger, SQLite store, assertion, and artifact writer. + +## Prerequisites + +- A built `agentctl` binary at `target/debug/agentctl`, or an installed binary +- The source checkout +- No provider credential + +## 1. Copy the verified journey + +From the repository root: + +```text +cp -R examples/acceptance/mock-tool /tmp/agentctl-first-agent +cd /tmp/agentctl-first-agent +``` + +The directory contains `workflow.yaml`, `fixture/service.txt`, and an empty artifact directory. The repository acceptance suite copies and runs the same journey outside the source tree. + +## 2. Read the boundary + +The workflow gives the `inspector` agent one tool, `read_fixture`. Its input and output use strict JSON Schema. Policy limits file access to the workspace, grants no mutation to the agent, and needs no network host or environment secret. + +The fake provider is configured to request `fixture/service.txt`, then return the fixed text `AGENTCTL_MOCK_FIXTURE_VERIFIED`. This makes the learning path deterministic while preserving the real tool continuation protocol. + +## 3. Validate and plan + +```text +agentctl check workflow.yaml +agentctl plan workflow.yaml +``` + +These commands make no network call and write no runtime state. The plan can identify the graph and declared effects, but the agent task still requires execution. + +## 4. Run the agent + +```text +agentctl run workflow.yaml --db .agentctl/runtime.db --output json --color never +``` + +Expected final output contains: + +```json +{ + "artifact": "artifacts/mock-report.txt", + "verdict": "AGENTCTL_MOCK_FIXTURE_VERIFIED" +} +``` + +The run writes `.agentctl/runtime.db` and `artifacts/mock-report.txt`. The `verify` task deterministically rejects any unexpected verdict. + +## 5. Inspect the agent and tool records + +```text +agentctl inspect RUN_ID --db .agentctl/runtime.db --output json --color never +``` + +Look for the provider session, tool call, effect correlation, task transitions, assertion result, artifact write, and run trace ID. The durable record lets you distinguish model output from deterministic verification. + +## Optional: use OpenAI + +Only after the credential-free path works, review `examples/v1/openai-live.yaml`. Export the credential through the environment, never through a flag or YAML value: + +```text +export OPENAI_API_KEY="your-provider-secret" +agentctl check examples/v1/openai-live.yaml +agentctl run examples/v1/openai-live.yaml --db .agentctl/openai.db --output json --color never +``` + +The live command makes a paid network request to `api.openai.com` and writes provider results to the database. Do not run it in normal documentation verification. Remove the variable from the shell when finished. + +## Troubleshooting + +- `binary not found`: use the absolute path to `target/debug/agentctl` or install the CLI. +- `path is outside workspace`: run from the copied example directory. +- artifact permission error: make `artifacts/` writable by the current user. +- live authentication failure: run `agentctl auth check` against the workflow without printing the secret. + +## Next step + +Read [Workflow authoring](WORKFLOW_AUTHORING.md) to replace the scripted journey with your own reviewed workflow. diff --git a/docs/guides/GETTING_STARTED.md b/docs/guides/GETTING_STARTED.md new file mode 100644 index 0000000..d7d0430 --- /dev/null +++ b/docs/guides/GETTING_STARTED.md @@ -0,0 +1,86 @@ +# Run your first deterministic workflow + +You will validate, plan, run, and inspect a credential-free workflow from a clean directory. The run performs one deterministic assignment, persists its history to SQLite, and returns a typed output. + +## Prerequisites + +- A built or installed `agentctl` binary +- The `agentctl` source checkout +- No provider credential + +## 1. Create a clean workspace + +From the repository root: + +```text +mkdir -p /tmp/agentctl-first-run +cp examples/v1/hello.yaml /tmp/agentctl-first-run/workflow.yaml +cd /tmp/agentctl-first-run +``` + +The copy is the canonical checked example. The commands write only beneath the temporary workspace. + +## 2. Validate the workflow + +```text +agentctl check workflow.yaml +``` + +Expected output: + +```text +valid: hello (1 tasks) +``` + +`check` validates strict YAML, references, templates, policies, and provider capabilities. It does not create a database or execute an effect. + +## 3. Inspect the plan + +```text +agentctl plan workflow.yaml +``` + +The plan reports task order `greet`, one effect, and `FullyPredictable`. A plan explains what the compiler knows. It does not claim to predict model or remote-system results. + +## 4. Run the workflow + +```text +agentctl run workflow.yaml --db .agentctl/runtime.db --output json --color never +``` + +This command writes durable state to `.agentctl/runtime.db`. It makes no network call and needs no credential. The final envelope has `apiVersion: agentctl.dev/cli/v1`, state `succeeded`, and output: + +```json +{"greeting":"hello, world"} +``` + +Copy the returned `runId` for inspection. + +## 5. Inspect durable history + +```text +agentctl inspect RUN_ID --db .agentctl/runtime.db --output json --color never +agentctl db stats --db .agentctl/runtime.db --output json --color never +``` + +Replace `RUN_ID` with the identifier from the run result. Inspection shows the run, task state, effects, checkpoints, audit records, and trace correlation. The database may contain workflow inputs and outputs, so protect it as sensitive operational data. + +## 6. Understand artifacts + +This workflow declares no file artifact. A workflow that uses `builtin.write` writes only beneath a policy-approved writable root. The runtime records the write as an effect, while the file itself stays in the workspace or mounted artifact directory. + +## Verify the result + +The tutorial is complete when all of these are true: + +- `check` reports one valid task. +- `plan` reports `FullyPredictable`. +- `run` exits `0` with `hello, world`. +- `.agentctl/runtime.db` exists. +- `inspect` returns the same successful run. + +If a command fails, read [Troubleshooting](TROUBLESHOOTING.md). + +## Next step + +Run [your first bounded agent workflow](FIRST_AGENT_WORKFLOW.md) without a paid API key. diff --git a/docs/guides/INSTALLATION.md b/docs/guides/INSTALLATION.md new file mode 100644 index 0000000..6981c2d --- /dev/null +++ b/docs/guides/INSTALLATION.md @@ -0,0 +1,71 @@ +# Install agentctl + +This guide installs the current `v1alpha1` release-candidate source. There is no published registry package or guaranteed downloadable binary in this checkout, so use a reviewed source build or build the OCI image yourself. + +## Prerequisites + +- Git +- Rust 1.88, as pinned by `rust-toolchain.toml` +- A supported local checkout +- Optional: Docker or Podman for the container path + +The repository configures hosted checks for Linux x64, macOS arm64, and Windows x64. Those workflows have not executed on the current remote candidate, so treat cross-platform support as configured and pending hosted evidence. + +## Install from source + +From the `agentctl` repository root, run: + +```text +cargo install --locked --path crates/agentctl-cli +agentctl version +``` + +The install compiles the Rust CLI and writes it to Cargo's binary directory. It makes dependency network requests during the build, writes no runtime database, and needs no provider credential. + +If you only want a repository-local binary, use: + +```text +cargo build --locked -p agentctl +./target/debug/agentctl version +``` + +## Build a release binary + +From the repository root: + +```text +cargo build --release --locked -p agentctl +./target/release/agentctl version +``` + +`cargo xtask package` also produces the binary, shell completions, license, README, and SHA-256 manifest beneath `dist/`. The package is local build output, not a published release. + +## Build the container image + +From the repository root, with Docker: + +```text +docker build --tag agentctl:local --file Containerfile . +docker run --rm agentctl:local version --output json --color never +``` + +The build downloads Rust dependencies. The version command makes no provider call and writes no state. The resulting image runs as UID/GID 65532 with `agentctl` as its entrypoint. Read the [container contract](../CONTAINER.md) before executing a workflow. + +## Verify the installation + +From the repository root: + +```text +agentctl check examples/v1/hello.yaml +agentctl plan examples/v1/hello.yaml +``` + +Expected evidence includes `valid: hello`, task order `greet`, and `FullyPredictable`. These commands do not create a runtime database. + +## Upgrade safely + +The workflow API is `agentctl.dev/v1alpha1`. Pin the CLI or image version, read [compatibility](../COMPATIBILITY.md) and [limitations](../LIMITATIONS.md), back up the SQLite database with its WAL files, then validate workflows before replacing a binary. `agentctl update` explains supported update paths but does not modify the installation. + +## Next step + +Continue with [Getting started](GETTING_STARTED.md). diff --git a/docs/guides/LOCAL_OPERATION.md b/docs/guides/LOCAL_OPERATION.md new file mode 100644 index 0000000..fca2fac --- /dev/null +++ b/docs/guides/LOCAL_OPERATION.md @@ -0,0 +1,69 @@ +# Operate agentctl locally + +Use explicit paths and retain the database whenever you may need inspection, approval, resume, replay, or audit evidence. + +## Default and custom paths + +The CLI defaults to `.agentctl/runtime.db` relative to the current working directory. The workflow workspace defaults to the current directory. Artifact locations come from workflow inputs and policy-approved paths. Override the state path and workspace explicitly for unattended use: + +```text +agentctl run config/workflow.yaml \ + --workspace /srv/project \ + --db /var/lib/agentctl/runtime.db \ + --output json --color never +``` + +This writes the SQLite database and any declared artifacts. Network calls occur only when the workflow uses an allowed provider or protocol. + +## Output and exit status + +Human output is for terminals. `--output json --color never` emits one versioned final document on stdout; an error uses the same envelope shape on stderr. Exit codes distinguish success, validation, policy or approval, run failure, persistence, remote failure, and cancellation. + +JSONL progress output is not supported in this release. Use durable audit and trace records for event-level inspection. + +## Interrupt safely + +SIGINT and SIGTERM request cancellation, cancel in-flight async work, persist cancellation state, and exit `130`. If dispatch occurred but confirmation did not, the related effect is uncertain. Do not delete the database or immediately rerun an external mutation. + +## Inspect a run + +```text +agentctl inspect RUN_ID --db /var/lib/agentctl/runtime.db --output json --color never +agentctl approvals list RUN_ID --db /var/lib/agentctl/runtime.db --output json --color never +``` + +Use the run ID and trace ID when correlating logs. Treat database output as sensitive because prompts, file content, tool output, and remote artifacts may be present even when secret values were redacted. + +## Resume, replay, retry, and fork + +- Resume continues the same non-terminal run and reuses confirmed effects. +- Retry is bounded within a task and never guesses about an ambiguous effect. +- Recorded replay creates a new record from terminal stored results and calls no executor. +- Fork creates a new child run and permits fresh effects. + +Do not use these terms interchangeably. Read [Durable execution](../DURABLE_EXECUTION.md) before recovering a workflow that may have changed an external system. + +## Resolve an approval + +Non-interactive execution persists a pending approval and exits `3` by default: + +```text +agentctl approvals list RUN_ID --db .agentctl/runtime.db +agentctl approvals approve APPROVAL_ID --db .agentctl/runtime.db \ + --actor operator@example.invalid --reason "Reviewed requested write" +agentctl resume RUN_ID --db .agentctl/runtime.db --output json --color never +``` + +Reject with `approvals reject` when the proposed effect is not acceptable. + +## Back up and retain state + +SQLite uses WAL mode. Copy the database and its WAL files as one consistent backup using an SQLite-aware method or during a controlled stop. Keep backups and artifacts according to data classification, not merely run age. + +After the retention period: + +```text +agentctl gc --db .agentctl/runtime.db --older-than-days 30 --output json --color never +``` + +Garbage collection deletes eligible terminal history and expired long-term memory. Back up before deletion when the history is audit evidence. diff --git a/docs/guides/TROUBLESHOOTING.md b/docs/guides/TROUBLESHOOTING.md new file mode 100644 index 0000000..34152eb --- /dev/null +++ b/docs/guides/TROUBLESHOOTING.md @@ -0,0 +1,134 @@ +# Troubleshoot agentctl + +Start with the exit code, then inspect the versioned error envelope and durable run state. Do not share provider credentials, complete databases, private prompts, or confidential artifacts in a public issue. + +## Decision path + +```mermaid +flowchart TD + A[Command failed] --> B{Was a run ID returned?} + B -->|No| C[Check syntax, paths, input, and authentication references] + B -->|Yes| D[Inspect the run and trace ID] + D --> E{Pending approval?} + E -->|Yes| F[Review and resolve approval, then resume] + E -->|No| G{Uncertain effect?} + G -->|Yes| H[Reconcile the external system before any fork] + G -->|No| I[Use task, effect, provider, and audit evidence] +``` + +The path separates pre-run validation from durable runtime failures. An uncertain effect always requires external reconciliation. + +## Validation error, exit 2 + +**Symptom:** `check`, `plan`, or `run` reports invalid YAML, a missing reference, unsupported capability, or bad template. + +**Likely cause:** The strict `v1alpha1` schema rejected a field or the compiler could not prove the graph and capabilities. + +**Diagnose:** + +```text +agentctl check workflow.yaml --output json --color never +agentctl schema --write /tmp/workflow.schema.json --output json --color never +``` + +**Expected evidence:** A source-aware diagnostic with a code and field location. + +**Resolve:** Fix the document instead of suppressing the diagnostic. Validate again before running. + +## Provider authentication failure + +**Symptom:** Exit `6` reports a missing environment reference or authentication response. + +**Likely cause:** The workflow names a credential environment variable that is absent or the provider rejected it. + +**Diagnose:** + +```text +agentctl auth check workflow.yaml --output json --color never +agentctl providers inspect workflow.yaml --output json --color never +``` + +**Expected evidence:** The environment variable name and provider capability, never the secret value. + +**Resolve:** Inject the named secret through the shell, scheduler, or CI secret facility. Do not add a key to YAML or a command argument. + +## Provider capability mismatch + +**Symptom:** Compilation rejects structured output, tools, reasoning, prompt cache, continuation, or a usage limit. + +**Likely cause:** The selected provider does not declare the requested feature, or an option is invalid. + +**Diagnose:** Run `providers inspect` and compare the [provider matrix](../PROVIDERS.md). + +**Resolve:** Remove the unsupported request, choose a capable provider, or change the workflow design. Do not assume provider APIs are interchangeable. + +## Tool failure or policy denial + +**Symptom:** Exit `3` or `4`, with a denied capability, invalid tool input/output, path error, host denial, or process denial. + +**Diagnose:** + +```text +agentctl inspect RUN_ID --db .agentctl/runtime.db --output json --color never +``` + +**Expected evidence:** Tool ID, capability, effect risk, policy decision, and redacted input. + +**Resolve:** Correct the schema or implementation. Expand a policy grant only after reviewing the exact resource and risk. + +## Pending approval + +**Symptom:** A non-interactive run exits `3` and state is paused. + +**Diagnose:** `agentctl approvals list RUN_ID --db PATH`. + +**Resolve:** Review the proposed effect. Approve or reject it with an actor and reason, then resume the same run and database. + +## Database locked or persistence error + +**Symptom:** Exit `5` reports a SQLite open, lock, corruption, or future-schema error. + +**Likely cause:** Wrong permissions, a read-only mount, lock contention beyond the five-second busy timeout, damaged files, or a newer schema. + +**Diagnose:** + +```text +agentctl db stats --db /state/runtime.db --output json --color never +ls -ld /state /state/runtime.db +``` + +**Expected evidence:** A readable and writable state directory owned by the runtime UID. A newer schema is reported explicitly. + +**Resolve:** Correct ownership and mounts, serialize conflicting maintenance, restore a consistent backup, or use a compatible binary. Never edit SQLite tables by hand as a first response. + +## Resume or replay failure + +**Symptom:** Resume rejects a terminal run or unresolved effect, or replay rejects a non-terminal source. + +**Diagnose:** Inspect the source run, tasks, effects, and approvals. + +**Resolve:** Resume only a safe non-terminal run. Replay only a terminal run. Reconcile uncertain external state before an explicit fork. + +## Container permission or read-only failure + +**Symptom:** The image cannot create `/state/runtime.db` or write `/artifacts`. + +**Likely cause:** Host directories are not writable by UID/GID 65532 or the writable mounts are missing. + +**Resolve:** Provision and mount `/state` and `/artifacts` with appropriate ownership. Keep the root filesystem read-only and use `/tmp` as a small `noexec,nosuid` tmpfs. + +## Corporate CA failure + +**Symptom:** The image build cannot verify the intercepted dependency-network certificate. + +**Resolve:** Pass a reviewed CA bundle through BuildKit secret `agentctl_ca` or `AGENTCTL_BUILD_CA_FILE` for the acceptance wrapper. Never disable TLS verification or commit the certificate. + +## Windows path issue + +**Symptom:** A workspace or database path parses differently from a Unix example. + +**Resolve:** Use native absolute paths and quote paths with spaces. Windows cannot express Unix database mode bits, so rely on the user profile ACL. Hosted Windows evidence is configured but still pending for the current candidate. + +## Safe issue report + +Include the exact `agentctl version`, operating system, redacted command, exit code, diagnostic code, workflow API version, minimal non-secret workflow, and relevant run/trace IDs. Share a narrow redacted `inspect` excerpt only when needed. Report security problems through the private process in [Security](../SECURITY.md), not a public issue. diff --git a/docs/guides/WORKFLOW_AUTHORING.md b/docs/guides/WORKFLOW_AUTHORING.md new file mode 100644 index 0000000..9258fd3 --- /dev/null +++ b/docs/guides/WORKFLOW_AUTHORING.md @@ -0,0 +1,123 @@ +# Author a workflow + +This guide teaches the YAML model in the order you need it. The generated JSON Schema is the field authority, but start with the execution model rather than the schema dump. + +## 1. Give the workflow an identity + +Every document has a strict versioned envelope: + +```yaml +apiVersion: agentctl.dev/v1alpha1 +kind: Workflow +metadata: + name: repository-check + description: Check a repository with reviewed automation. +spec: + tasks: [] +``` + +Unknown fields fail validation. The document limit is 1 MiB. + +## 2. Declare inputs + +`spec.inputs` defines default JSON values. A caller can override them with `--inputs`, `--inputs-file`, or repeated `--input KEY=VALUE`. + +```yaml +spec: + inputs: + reportPath: artifacts/report.txt +``` + +Templates can read `${{ inputs.reportPath }}`. An exact template preserves its JSON type. Interpolation into text accepts scalars only. + +## 3. Define tasks + +Tasks are the graph nodes. Their list order is also the deterministic tie-break order for tasks whose dependencies are ready. + +```yaml +tasks: + - id: inspect + uses: action:read + with: + path: README.md +``` + +## 4. Add dependencies + +Use `needs` for graph edges and task-output availability: + +```yaml +- id: verify + uses: action:assert + needs: [inspect] + with: + that: "${{ tasks.inspect.output.content }}" + message: README was empty +``` + +The compiler rejects missing references, implicit dependencies, duplicate IDs, and cycles. + +## 5. Choose deterministic actions + +Built-in actions cover assignment, assertion, file read and write, direct process execution, working memory, SQLite long-term memory, MCP calls, and A2A delegation. Declare each action once, then reference it with `action:name`. + +Process execution uses a command plus direct argument vector. It never inserts an implicit shell and receives only explicitly allowed environment variables. + +## 6. Add a bounded agent + +An agent names a provider, model, instructions, tools, and hard bounds: + +```yaml +providers: + fake: + kind: fake +agents: + reviewer: + provider: fake + model: scripted + instructions: Review only the supplied evidence. + tools: [read_repository] + maxTurns: 2 + maxToolCalls: 1 + maxOutputTokens: 128 + timeoutSeconds: 10 +``` + +The model does not own the graph, policy, or persistence. + +## 7. Define tool contracts + +A model sees only tools listed on its agent. Each tool requires strict input and output schema, capability, risk, effect class, idempotency, retry safety, timeout, and approval requirement. Runtime policy makes the final authorization decision. + +## 8. Declare outputs + +Workflow outputs select completed task data: + +```yaml +outputs: + report: "${{ tasks.report.output.path }}" +``` + +Machine output wraps declared values in the versioned CLI envelope. + +## 9. Constrain policy + +Policy owns workspace roots, writable roots, environment names, network hosts, processes, providers, tools, and approvals. Allowlists are application controls, not an operating-system sandbox. + +Start with the minimum grant. Add a host, writable root, executable, or secret name only when a verified task needs it. + +## 10. Plan for state and recovery + +Choose an explicit database path for scheduled or CI runs. A confirmed effect can be reused during resume. An effect that started without a confirmed result becomes uncertain and stops automatic recovery. Recorded replay calls no executor. Fork intentionally permits fresh effects. + +## Validate your workflow + +From the directory containing the workflow: + +```text +agentctl check workflow.yaml +agentctl plan workflow.yaml +agentctl run workflow.yaml --check --diff --db .agentctl/preview.db +``` + +The preview may write run history to its database, but it does not perform filesystem, process, remote, or model mutation. Read [Workflow DSL](../DSL.md) and the [YAML reference](../reference/YAML.md) for the complete contract. diff --git a/docs/reference/CLI_OUTPUT.md b/docs/reference/CLI_OUTPUT.md new file mode 100644 index 0000000..051bdc4 --- /dev/null +++ b/docs/reference/CLI_OUTPUT.md @@ -0,0 +1,38 @@ +# CLI output and exit codes + +The [generated CLI reference](../generated/CLI.md) is produced from Clap help by `cargo xtask generate`. This page explains the stable process contract used by scripts and CI. + +## Output modes + +Human mode is the default and may use color on a terminal. JSON mode emits one final object and never includes ANSI color: + +```text +agentctl run workflow.yaml --output json --color never +``` + +The envelope version is `agentctl.dev/cli/v1` and includes `kind`, `ok`, `data`, and `diagnostics`. A successful run includes run ID, trace ID, terminal state, and declared output. A failure writes a versioned error envelope to stderr, with run and trace correlation when a run exists. + +JSONL progress output is not implemented in this release. Event-level information remains available in durable audit and trace records. + +## Exit codes + +| Code | Category | Pipeline response | +| --- | --- | --- | +| `0` | success | Collect outputs and artifacts. | +| `2` | usage or validation | Correct arguments, YAML, references, templates, or capabilities. | +| `3` | policy or approval | Inspect denial or retain state for operator approval. | +| `4` | run failure | Inspect the failed task and effect history. | +| `5` | persistence | Check database compatibility, permissions, corruption, and locking. | +| `6` | provider or protocol | Diagnose authentication, network, native API, MCP, or A2A evidence. | +| `130` | cancellation | Inspect the run before deciding whether resume is safe. | + +Do not automatically retry every nonzero code. A provider, protocol, process, or tool operation may be uncertain after dispatch. + +## Example + +```text +agentctl check examples/v1/hello.yaml --output json --color never +agentctl run examples/v1/hello.yaml --db /tmp/hello.db --output json --color never +``` + +These commands need no credential. `check` writes no runtime database; `run` writes `/tmp/hello.db`. diff --git a/docs/reference/DATABASE.md b/docs/reference/DATABASE.md new file mode 100644 index 0000000..083b1a3 --- /dev/null +++ b/docs/reference/DATABASE.md @@ -0,0 +1,41 @@ +# Runtime database and migrations + +The local SQLite database is both history and part of the correctness boundary. The current database schema version is `4`. + +## Stored records + +- runs, source workflow, compiled plan, inputs, output, mode, state, and parent linkage +- task states, attempts, output, and errors +- effects, request/result/error, confirmation, and uncertainty +- approvals and resolutions +- checksummed checkpoints +- ordered audit and trace events +- provider sessions and tool calls +- namespaced long-term memory with optional expiry + +Working memory is stored on the run and in checkpoints. Provider credentials are not stored. Other confidential content may be stored, including prompts, tool output, and remote artifacts. + +## Migrations + +The store reads SQLite `user_version` and applies forward migrations in order inside transactions. A database newer than the binary fails explicitly. Corrupt or incompatible serialized state also fails explicitly. + +```text +agentctl db stats --db .agentctl/runtime.db --output json --color never +agentctl db migrate --db .agentctl/runtime.db --output json --color never +``` + +`db migrate` may write the database. Back up the database and its WAL state before an upgrade. + +## Locking and permissions + +The connection enables foreign keys, WAL mode, and a five-second busy timeout. Unix database files use mode `0600`. Windows relies on user-profile ACLs. Separate runs can share a database, but this is not a distributed lease and does not prevent two runs from changing the same external resource. + +## Backups and recovery + +Use an SQLite-aware online backup or stop writers before copying the database and WAL files. Restore the set consistently. Do not use ordinary file synchronization that can separate a database from uncheckpointed WAL content. + +Delete old terminal history only after retention requirements are met: + +```text +agentctl gc --db .agentctl/runtime.db --older-than-days 30 --output json --color never +``` diff --git a/docs/reference/ENVIRONMENT_AND_PATHS.md b/docs/reference/ENVIRONMENT_AND_PATHS.md new file mode 100644 index 0000000..5af4c36 --- /dev/null +++ b/docs/reference/ENVIRONMENT_AND_PATHS.md @@ -0,0 +1,44 @@ +# Environment variables and default paths + +## Provider credentials + +| Provider kind | Conventional reference | Required when | +| --- | --- | --- | +| `fake` | none | Never. | +| `openai` | `OPENAI_API_KEY` | The workflow dispatches an OpenAI request. | +| `azure_openai` | `AZURE_OPENAI_API_KEY` | The workflow dispatches an Azure OpenAI request. | +| `anthropic` | `ANTHROPIC_API_KEY` | The workflow dispatches an Anthropic request. | +| `google` | `GEMINI_API_KEY` | The workflow dispatches a Google request. | + +These names are defaults used by repository examples. A workflow can name another valid environment reference. Policy must allow the name. Values never belong in YAML, CLI arguments, ordinary inputs, logs, or committed fixtures. + +## Repository and acceptance variables + +| Variable | Scope | Purpose | +| --- | --- | --- | +| `AGENTCTL_CONTAINER_ENGINE` | local acceptance | Select `docker` or `podman` when auto-detection is unsuitable. | +| `AGENTCTL_BUILD_CA_FILE` | local container build | Path to a reviewed CA bundle supplied as a build secret. | +| `AGENTCTL_BUILD_CA_PEM` | hosted container workflow | Protected secret materialized temporarily by CI. | + +Normal `cargo xtask docs-verify`, `cargo xtask verify`, and `cargo xtask acceptance` need no provider credential. + +## CLI paths + +| Path | Default or contract | Notes | +| --- | --- | --- | +| Workflow file | positional argument | Read-only input, at most 1 MiB. | +| Workspace | current directory | Override with `--workspace`. | +| Runtime database | `.agentctl/runtime.db` | Override with `--db`; SQLite WAL belongs to the same state set. | +| Artifact path | workflow-defined | Must remain under a policy-approved writable root. | + +## Container paths + +| Path | Access | +| --- | --- | +| `/config` | reviewed read-only configuration | +| `/workspace` | normally read-only workspace | +| `/state` | writable durable state | +| `/artifacts` | writable collected output | +| `/tmp` | small runtime tmpfs when the root filesystem is read-only | + +State and artifacts must be writable by UID/GID 65532 in the production image. diff --git a/docs/reference/MATRICES.md b/docs/reference/MATRICES.md new file mode 100644 index 0000000..541d68e --- /dev/null +++ b/docs/reference/MATRICES.md @@ -0,0 +1,39 @@ +# Capability matrices + +## Provider capabilities and evidence + +| Provider | Text | Tools | Structured output | Reasoning | Continuation | Current evidence | +| --- | --- | --- | --- | --- | --- | --- | +| Fake | yes | scripted | deterministic fixture behavior | no | scripted | deterministic runtime and acceptance | +| OpenAI | yes | strict function tools | native response format | supported options | stored Responses continuation | mock protocol plus retained bounded live GPT-5.6 evidence | +| Azure OpenAI | yes | strict function tools | OpenAI response mapping | supported options | stored Responses continuation | mock protocol only | +| Anthropic | yes | native tool blocks | instruction mapping | native thinking blocks | provider-neutral continuation | mock protocol only | +| Google Gemini | yes | native function calls | response schema | thought-signature mapping | provider-neutral continuation | mock protocol only | + +Capabilities are negotiated from source metadata before execution. `agentctl providers inspect WORKFLOW` reports what the selected configuration requests and supports without making a service call. Provider features are not assumed equivalent. + +## Built-in tool executors + +| Tool kind | Capability | Effect class | Typical idempotency | Policy boundary | +| --- | --- | --- | --- | --- | +| `builtin.workspace.read` | `filesystem.read` | observe | idempotent | canonical workspace root | +| `builtin.workspace.write` | `filesystem.write` | workspace mutation | keyed or at-most-once by contract | approved writable roots | +| `builtin.echo` | declared echo capability | pure | pure | tool allowlist and schema | + +The compiler verifies that a built-in tool declaration matches its executor semantics. A model cannot change capability, risk, effect class, idempotency, or approval behavior. + +## Built-in actions + +| Action kind | External interaction | Replay behavior | +| --- | --- | --- | +| `builtin.assign` | none | recorded output | +| `builtin.assert` | none | recorded terminal result | +| `builtin.read` | workspace observation | recorded result, no fresh read in replay | +| `builtin.write` | workspace mutation | recorded result, no fresh write in replay | +| `builtin.shell.exec` | direct process | recorded result, no fresh process in replay | +| working-memory read/write | run-local state | checkpointed and reconstructed | +| long-term-memory read/write | SQLite cross-run state | recorded result; long-term store is not rolled back | +| `mcp.call` | remote tool | recorded result, no fresh call in replay | +| `a2a.delegate` | remote agent | recorded result, no fresh delegation in replay | + +See [Providers](../PROVIDERS.md), [Tools](../TOOLS.md), and [Durable execution](../DURABLE_EXECUTION.md). diff --git a/docs/reference/TERMINOLOGY.md b/docs/reference/TERMINOLOGY.md new file mode 100644 index 0000000..72d7189 --- /dev/null +++ b/docs/reference/TERMINOLOGY.md @@ -0,0 +1,27 @@ +# Terminology + +Use these terms consistently in workflows, documentation, issues, and reviews. + +| Term | Meaning | +| --- | --- | +| Workflow | One versioned declarative YAML document and its compiled graph. | +| Task | One ordered graph node that invokes an action or agent. | +| Action | A typed runtime operation selected directly by a task. | +| Agent | A bounded provider-backed executor for one task. | +| Tool | A strict capability contract that an agent may request. | +| Provider | A native model API adapter behind provider-neutral contracts. | +| Effect | A durably identified operation that observes or changes state outside pure computation. | +| Run | One durable execution, check, replay, or fork record. | +| Attempt | One bounded execution attempt for a task. | +| Resume | Continue the same non-terminal run using durable progress. | +| Recorded replay | Create a new record from terminal stored results without calling executors. | +| Retry | Start another bounded attempt for a task after a definitive retry-safe failure. | +| Fork | Create a child run that intentionally permits fresh effects. | +| Rerun | Informal term. Prefer fork when referring to the supported fresh-run operation. | +| Approval | A durable operator decision required before an effect may continue. | +| Checkpoint | A versioned, checksummed snapshot used for recovery. | +| Working memory | One run-local JSON object changed by explicit memory actions. | +| Long-term memory | Namespaced SQLite values shared across runs and managed by retention. | +| Pack | A local versioned manifest and reviewed reusable content with integrity checking. | + +Do not use resume, replay, retry, and fork interchangeably. None of them means exactly-once execution. diff --git a/docs/reference/YAML.md b/docs/reference/YAML.md new file mode 100644 index 0000000..381acbf --- /dev/null +++ b/docs/reference/YAML.md @@ -0,0 +1,108 @@ +# YAML reference + +The generated [workflow JSON Schema](../../schemas/workflow.schema.json) is authoritative. This page explains the field groups, defaults, and validation behavior that matter when writing YAML. + +## Document envelope + +| Field | Required | Meaning | +| --- | --- | --- | +| `apiVersion` | yes | Must be `agentctl.dev/v1alpha1`. | +| `kind` | yes | Must be `Workflow`. | +| `metadata.name` | yes | Stable human-readable workflow name. | +| `metadata.description` | no | Short purpose. | +| `metadata.labels` | no | String metadata map. | +| `spec` | yes | Workflow declarations and ordered tasks. | + +Unknown fields fail. Documents, ordinary input files, packs, direct reads, existing write targets, and instruction files are limited to 1 MiB. + +## Workflow declarations + +| `spec` field | Default | Purpose | +| --- | --- | --- | +| `inputs` | `{}` | Default JSON values supplied to templates. | +| `outputs` | `{}` | Final values selected from inputs, memory, variables, or task outputs. | +| `providers` | `{}` | Named fake, OpenAI, Azure OpenAI, Anthropic, or Google adapters. | +| `agents` | `{}` | Named bounded model executors. | +| `actions` | `{}` | Named deterministic or protocol actions. | +| `tools` | `{}` | Strict model-callable tool contracts. | +| `tasks` | required list | Ordered graph nodes. | +| `policy` | safe defaults | Filesystem, process, network, provider, tool, and approval rules. | +| `memory` | empty | Initial working memory and optional SQLite long-term namespace. | +| `mcpServers` | `{}` | Pinned MCP Streamable HTTP peers. | +| `a2aPeers` | `{}` | Pinned A2A Agent Card peers. | +| `packs` | `[]` | Local reviewed pack references. | +| `runtime` | sequential defaults | Runtime controls. `maxConcurrency` must be `1`. | +| `output` | defaults | Output presentation contract. | + +## Tasks + +Each task requires `id` and `uses`. `uses` is `action:name` or `agent:name`. + +| Field | Default | Validation | +| --- | --- | --- | +| `needs` | `[]` | Every ID must exist; cycles fail. | +| `when` | true | Constrained boolean/equality expression. | +| `vars` | `{}` | Task-local JSON values. | +| `with` | `{}` | Typed action or agent input. | +| `retry` | bounded default | Only definitive retry-safe failures may repeat. | +| `timeoutSeconds` | action or agent default | Must be within the implementation bound. | +| failure behavior | fail | Unsupported dynamic control flow is rejected. | + +Ready tasks run in YAML declaration order. There is no `foreach`, matrix, loop, router, sub-workflow, handler, or parallel group in this version. + +## Agents + +An agent requires `provider` and `model`. Defaults are `maxTurns: 8`, `maxToolCalls: 16`, `maxOutputTokens: 2048`, and `timeoutSeconds: 120`. Set tighter values for known work. Optional fields include instructions or `instructionsFile`, variables, tools, retry, reasoning, structured output, usage limits, and provider-specific options. + +Capability negotiation happens during compilation. A provider must explicitly support every requested feature. + +## Actions + +Supported action kinds: + +- `builtin.assign` +- `builtin.assert` +- `builtin.read` +- `builtin.write` +- `builtin.shell.exec` +- `builtin.memory.read` +- `builtin.memory.write` +- `builtin.long_term_memory.read` +- `builtin.long_term_memory.write` +- `mcp.call` +- `a2a.delegate` + +`builtin.shell.exec` uses a direct executable and argument list. Output defaults are 1 MiB per stream and 2 MiB combined, with a maximum configured value of 16 MiB. Its maximum timeout is 86,400 seconds. + +## Tools + +A tool requires `kind`, description, strict input and output JSON Schema, capability, risk, effect class, idempotency, retry safety, timeout, and approval behavior. Built-in tool executors are workspace read, workspace write, and echo. Declared semantics must match the built-in kind. + +## Templates and conditions + +Allowed template roots are: + +```text +${{ inputs.path }} +${{ vars.path }} +${{ memory.path }} +${{ tasks.task-id.output.path }} +``` + +An exact template preserves objects, arrays, booleans, numbers, strings, and null. Text interpolation accepts scalars. Conditions add `not` and equality against a JSON literal or string. There is no code execution, arithmetic, arbitrary function, indexing, or implicit dependency. + +## Secret references + +Provider credentials, action environment values, and protocol headers use `{ env: NAME }`. The environment name is stored in the workflow, but the value is resolved only at the adapter boundary and must be allowed by policy. + +## Example and validation + +See `examples/v1/dataflow.yaml` for typed inputs and task outputs. From the repository root: + +```text +agentctl check examples/v1/dataflow.yaml +agentctl plan examples/v1/dataflow.yaml +agentctl run examples/v1/dataflow.yaml --db /tmp/dataflow.db --output json --color never +``` + +Related guides: [Workflow authoring](../guides/WORKFLOW_AUTHORING.md), [Policies](../POLICIES.md), [Tools](../TOOLS.md), and [Workflow DSL](../DSL.md). diff --git a/docs/use-cases/APPROVAL_GATED_ACTION.md b/docs/use-cases/APPROVAL_GATED_ACTION.md new file mode 100644 index 0000000..ea13bc4 --- /dev/null +++ b/docs/use-cases/APPROVAL_GATED_ACTION.md @@ -0,0 +1,36 @@ +# Approval-gated action + +## Problem + +A workflow may propose a mutation, but an operator must review the exact requested effect before it runs. + +## Why agentctl fits + +Policy sits outside the model and creates a durable approval record. Non-interactive execution pauses and exits `3`; it never prompts, auto-approves, or loses the pending request. + +## Complete workflow + +Source: `examples/v1/approval.yaml`. + + + +## Run it + +```text +agentctl run examples/v1/approval.yaml --db /tmp/approval.db \ + --output json --color never +agentctl approvals list RUN_ID --db /tmp/approval.db +agentctl approvals approve APPROVAL_ID --db /tmp/approval.db \ + --actor operator@example.invalid --reason "Reviewed file write" +agentctl resume RUN_ID --db /tmp/approval.db --output json --color never +``` + +The first command exits `3` and does not write the file. The resumed run writes it only after approval. + +## State and security + +The approval includes redacted input, tool or action, capability, risk, expected effect, actor, reason, run, task, and trace correlation. Approval is a decision point, not proof that content is safe. + +## Current limitation + +The CLI stores operator-provided identity text but does not provide a hosted identity or role system. The invoking platform must authenticate and authorize the operator. diff --git a/docs/use-cases/CI_QUALITY_GATE.md b/docs/use-cases/CI_QUALITY_GATE.md new file mode 100644 index 0000000..730e200 --- /dev/null +++ b/docs/use-cases/CI_QUALITY_GATE.md @@ -0,0 +1,32 @@ +# CI quality gate + +## Problem + +A generic OCI pipeline step must convert typed evidence into a stable success or failure, emit one machine-readable result, and preserve enough state for diagnosis. + +## Why agentctl fits + +The workflow separates inputs from a deterministic assertion. The CLI returns a stable exit code and JSON envelope, while the CI platform retains `/state` and `/artifacts`. + +## Complete workflow + +Source: `examples/docs/ci-quality-gate/workflow.yaml`. + + + +## Run it + +```text +agentctl run examples/docs/ci-quality-gate/workflow.yaml \ + --db /tmp/ci-quality-gate.db --output json --color never +``` + +The default exits `0` with verdict `pass`. Run with `--input checksPassed=false` to exercise the failed gate and exit `4`. + +## State and security + +Use ordinary typed inputs for non-secret gate evidence. Inject provider secrets only by environment reference. Archive the database on failure only when its potentially confidential content is protected. + +## Current limitation + +This workflow does not run tests itself. A surrounding pipeline can supply results, or a reviewed `builtin.shell.exec` action can run a specifically allowed executable. diff --git a/docs/use-cases/PROVIDER_PORTABILITY.md b/docs/use-cases/PROVIDER_PORTABILITY.md new file mode 100644 index 0000000..09853f7 --- /dev/null +++ b/docs/use-cases/PROVIDER_PORTABILITY.md @@ -0,0 +1,47 @@ +# Provider portability + +## Problem + +A workflow author wants one provider-neutral agent contract while retaining honest capability differences and evidence levels. + +## Why agentctl fits + +The core stores provider-neutral messages, tools, usage, errors, and continuation. Native adapters translate at the edge, and the compiler rejects requested features that the selected provider does not support. + +## Credential-free variant + +Source: `examples/docs/provider-portability/fake.yaml`. + + + +Run it with: + +```text +agentctl run examples/docs/provider-portability/fake.yaml \ + --db /tmp/provider-fake.db --output json --color never +``` + +Expected summary: `PORTABLE_SUMMARY_VERIFIED`. + +## Opt-in OpenAI variant + +Source: `examples/docs/provider-portability/openai.yaml`. + + + +Static validation needs no credential: + +```text +agentctl check examples/docs/provider-portability/openai.yaml +agentctl providers inspect examples/docs/provider-portability/openai.yaml +``` + +Execution requires `OPENAI_API_KEY` in the environment, makes a paid network request, and is excluded from normal documentation verification. + +## State and security + +Both workflows share the provider-neutral agent shape. Each provider still needs its native credential, allowed host, model name, capability checks, timeouts, and error handling. + +## Current limitation + +Provider portability does not mean identical behavior or equal maturity. Fake is deterministic, OpenAI has retained bounded live evidence, and Azure OpenAI, Anthropic, and Google are mock-protocol tested only in this release. diff --git a/docs/use-cases/RECORDED_REPLAY.md b/docs/use-cases/RECORDED_REPLAY.md new file mode 100644 index 0000000..2afbc15 --- /dev/null +++ b/docs/use-cases/RECORDED_REPLAY.md @@ -0,0 +1,34 @@ +# Offline recorded replay + +## Problem + +An operator needs to reconstruct the outcome of a completed provider-backed run without credentials, network access, or repeated effects. + +## Why agentctl fits + +Recorded replay reads terminal stored task output and effect records. It creates a linked replay record but never calls provider, tool, network, process, filesystem, MCP, or A2A executors. + +## Example workflow + +Source: `examples/v1/crash-resume.yaml`. + + + +## Run and replay + +```text +mkdir -p examples/v1/artifacts +agentctl run examples/v1/crash-resume.yaml --db /tmp/replay.db \ + --output json --color never +agentctl replay RUN_ID --db /tmp/replay.db --output json --color never +``` + +Use the terminal source run ID returned by the first command. The replay has its own run ID and links to the source. + +## State and security + +Replay needs only the database, but the stored record may contain confidential input and output. It reproduces recorded truth, not current files or remote state. + +## Current limitation + +Replay is not a new validation, retry, or exactly-once guarantee. It rejects non-terminal source runs. Use resume for safe continuation and fork only when fresh effects are intentional. diff --git a/docs/use-cases/RELEASE_READINESS.md b/docs/use-cases/RELEASE_READINESS.md new file mode 100644 index 0000000..c21c358 --- /dev/null +++ b/docs/use-cases/RELEASE_READINESS.md @@ -0,0 +1,32 @@ +# Release-readiness report + +## Problem + +A release process has deterministic evidence such as tests and a security scan, plus a bounded model summary. Model analysis must not override failed gates. + +## Why agentctl fits + +Dependencies keep the analysis task behind two assertions. The model can summarize only after deterministic gates pass. A pipeline consumes the final process status and declared output. + +## Complete workflow + +Source: `examples/docs/release-readiness/workflow.yaml`. + + + +## Run it + +```text +agentctl run examples/docs/release-readiness/workflow.yaml \ + --db /tmp/release-readiness.db --output json --color never +``` + +The credential-free example returns decision `RELEASE_EVIDENCE_REVIEWED`. Override `testsPassed=false` to verify that exit `4` prevents the model task from running. + +## State and security + +The database records which gate failed and whether the analysis task started. A real workflow should pass evidence through reviewed files or typed inputs, not give the model CI credentials or authority to change release state. + +## Current limitation + +The example uses the fake provider. It demonstrates graph and policy behavior, not a live model quality claim or a release approval system. diff --git a/docs/use-cases/REPOSITORY_AUDIT.md b/docs/use-cases/REPOSITORY_AUDIT.md new file mode 100644 index 0000000..438b770 --- /dev/null +++ b/docs/use-cases/REPOSITORY_AUDIT.md @@ -0,0 +1,39 @@ +# Repository audit + +## Problem + +A model needs to inspect a repository and produce a report, but it should see only reviewed files and its conclusion must pass deterministic checks before becoming an artifact. + +## Why agentctl fits + +The workflow graph and policy are outside the model. A strict read tool limits the agent to the workspace, the fake provider makes the documented journey repeatable, an assertion checks the final marker, and a separate deterministic action writes the report. + +## Complete workflow + +Source: `examples/acceptance/mock-tool/workflow.yaml`. + + + +The repository acceptance suite copies this entire directory to a clean workspace and runs it. + +## Run it + +From the repository root: + +```text +cp -R examples/acceptance/mock-tool /tmp/agentctl-repository-audit +cd /tmp/agentctl-repository-audit +agentctl check workflow.yaml +agentctl plan workflow.yaml +agentctl run workflow.yaml --db .agentctl/runtime.db --output json --color never +``` + +The run needs no credential and makes no network call. Expected output includes verdict `AGENTCTL_MOCK_FIXTURE_VERIFIED` and artifact `artifacts/mock-report.txt`. + +## State and security + +The database records the provider session, strict tool call, read effect, assertion, write effect, audit events, and trace correlation. The read tool cannot mutate the workspace. Replace the fake provider only after reviewing new credential, network, model, and output risks. + +## Current limitation + +The checked journey proves orchestration and tool boundaries, not the quality of a live model's repository analysis. Production workflows need task-specific verification stronger than a fixed marker. diff --git a/docs/use-cases/SCHEDULED_REVIEW.md b/docs/use-cases/SCHEDULED_REVIEW.md new file mode 100644 index 0000000..c301066 --- /dev/null +++ b/docs/use-cases/SCHEDULED_REVIEW.md @@ -0,0 +1,35 @@ +# Scheduled operational review + +## Problem + +An external scheduler needs to run a bounded check, retain state, and collect a report without an interactive session. + +## Why agentctl fits + +The CLI has a non-interactive process contract, explicit state and artifact paths, durable failures, structured output, and safe cancellation. Cron, systemd, or Kubernetes owns the schedule and overlap rule. + +## Complete workflow + +Source: `examples/docs/scheduled-review/workflow.yaml`. + + + +## Run it + +From a copy of the example directory: + +```text +mkdir -p artifacts .agentctl +agentctl run workflow.yaml --db .agentctl/runtime.db \ + --timeout-seconds 300 --output json --color never +``` + +Expected output declares `artifacts/operational-review.txt`. The file contains `scheduled operational review passed`. + +## State and security + +Persist the database and artifact directory with restrictive permissions. Configure `flock`, systemd serialization, or Kubernetes `concurrencyPolicy: Forbid` when overlapping external effects are unsafe. + +## Current limitation + +`agentctl` is a schedulable runtime, not a scheduling service. It does not provide clocks, calendars, distributed leases, or log rotation. diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..1a5399e --- /dev/null +++ b/examples/README.md @@ -0,0 +1,5 @@ +# Examples + +The supported Rust workflow API examples are in [`v1/`](v1/README.md). The documentation acceptance journeys are in [`docs/`](docs/README.md). + +Other example directories at this level describe the retired TypeScript playbook format and remain only as migration fixtures. They are not accepted by the current `agentctl.dev/v1alpha1` compiler. Do not use their commands as current CLI guidance; use the [migration guide](../docs/MIGRATION.md) to translate them. diff --git a/examples/custom-pack-tools/README.md b/examples/custom-pack-tools/README.md index a9084d3..02663ba 100644 --- a/examples/custom-pack-tools/README.md +++ b/examples/custom-pack-tools/README.md @@ -1,27 +1,5 @@ -# Custom Pack Tools +# Custom Pack Tools (legacy) -This example shows two process-backed pack tools: +This directory is a migration fixture for the retired TypeScript playbook format. The current Rust CLI does not accept `mission.playbook.yaml` or its process-backed pack contract. -- `custom/node_version`: wraps an existing host command (`node --version`) -- `custom/fixture_audit`: runs a script shipped inside the pack - -Both tools are exposed to an agent through the normal `tools:` block, and both are preflight-checked before the run starts. - -Because both tools launch subprocesses, each agent-origin tool call is approval-gated. In an interactive TTY run, `agentctl` prompts inline and resumes automatically after approval. - -Run: - -```bash -agentctl run examples/custom-pack-tools/mission.playbook.yaml --db .runtime/custom-pack-tools.db -``` - -Expected behavior: - -- the run pauses for approval before the agent launches the subprocess-backed tools -- after approval, the agent calls both tools in order -- the run succeeds without requiring any built-in write or shell tool access for the agent -- the report is persisted to `./artifacts/custom-pack-report.md` -- verification confirms the report mentions: - - the detected Node.js version - - the missing rollback owner - - the missing restore drill +Use [`../v1/reusable-pack.yaml`](../v1/reusable-pack.yaml) and [`../v1/example.pack.yaml`](../v1/example.pack.yaml) for the supported pack format. The [workflow authoring guide](../../docs/guides/WORKFLOW_AUTHORING.md) and generated schema define current action, tool, effect, and approval fields. diff --git a/examples/dataflow/README.md b/examples/dataflow/README.md index 30c8576..49578a9 100644 --- a/examples/dataflow/README.md +++ b/examples/dataflow/README.md @@ -1,25 +1,5 @@ -# Dataflow Example +# Dataflow Example (legacy) -This example proves YAML step-to-step output passing in two forms: +This directory is a migration fixture for the retired TypeScript playbook format. The current Rust CLI does not accept `mission.playbook.yaml`. -- scalar output propagation -- structured JSON object propagation - -The flow is: - -1. `produce` assigns a scalar and a nested object. -2. `consume_scalar` reads the scalar from `tasks.produce.output`. -3. `consume_object` reads the nested object from `tasks.produce.output`. -4. `assert_scalar` and `assert_object` verify both values survived unchanged. - -Run it with: - -```bash -agentctl run examples/dataflow/mission.playbook.yaml --db .runtime/dataflow.db -``` - -Successful output proves: - -- task output templating works -- nested arrays and objects are preserved across task boundaries -- deterministic assertions can validate the handoff without custom code +Use [`../v1/dataflow.yaml`](../v1/dataflow.yaml) for the supported `agentctl.dev/v1alpha1` example of scalar and structured task-output propagation, templates, dependencies, and deterministic assertions. diff --git a/examples/docs/README.md b/examples/docs/README.md new file mode 100644 index 0000000..4389d0c --- /dev/null +++ b/examples/docs/README.md @@ -0,0 +1,13 @@ +# Documentation examples + +These examples support public guides. `cargo xtask docs-verify` checks every YAML file and executes the credential-free examples from temporary directories. + +| Journey | Provider | Verification | Network | Security note | +| --- | --- | --- | --- | --- | +| `release-readiness` | fake | mock-backed run with deterministic gates | none | model result cannot override failed assertions | +| `scheduled-review` | none | deterministic run and artifact | none | scheduler owns overlap and retention | +| `ci-quality-gate` | none | deterministic success and failure paths | none | pipeline uses the exit code | +| `provider-portability/fake.yaml` | fake | deterministic run | none | learning default | +| `provider-portability/openai.yaml` | OpenAI | static validation only | opt-in live | credential is an environment reference | + +Prominent documentation examples should use source inclusion from these files or existing checked examples. Do not copy and edit a second YAML block in the site repository. diff --git a/examples/docs/ci-quality-gate/workflow.yaml b/examples/docs/ci-quality-gate/workflow.yaml new file mode 100644 index 0000000..5b0a19c --- /dev/null +++ b/examples/docs/ci-quality-gate/workflow.yaml @@ -0,0 +1,26 @@ +apiVersion: agentctl.dev/v1alpha1 +kind: Workflow +metadata: + name: ci-quality-gate + description: Convert reviewed CI evidence into a stable process result. +spec: + inputs: + checksPassed: true + outputs: + verdict: "${{ tasks.verdict.output.output.value }}" + actions: + assert: + kind: builtin.assert + assign: + kind: builtin.assign + tasks: + - id: gate + uses: action:assert + with: + that: "${{ inputs.checksPassed }}" + message: CI quality gate failed + - id: verdict + uses: action:assign + needs: [gate] + with: + value: pass diff --git a/examples/docs/provider-portability/fake.yaml b/examples/docs/provider-portability/fake.yaml new file mode 100644 index 0000000..014514b --- /dev/null +++ b/examples/docs/provider-portability/fake.yaml @@ -0,0 +1,27 @@ +apiVersion: agentctl.dev/v1alpha1 +kind: Workflow +metadata: + name: portable-summary-fake + description: Credential-free provider portability fixture. +spec: + outputs: + summary: "${{ tasks.summarize.output.text }}" + providers: + selected: + kind: fake + agents: + summarizer: + provider: selected + model: scripted + instructions: Return one short evidence summary. + maxTurns: 1 + maxToolCalls: 0 + maxOutputTokens: 64 + timeoutSeconds: 5 + providerOptions: + finalText: PORTABLE_SUMMARY_VERIFIED + tasks: + - id: summarize + uses: agent:summarizer + with: + prompt: Summarize the supplied evidence. diff --git a/examples/docs/provider-portability/openai.yaml b/examples/docs/provider-portability/openai.yaml new file mode 100644 index 0000000..94722d2 --- /dev/null +++ b/examples/docs/provider-portability/openai.yaml @@ -0,0 +1,31 @@ +apiVersion: agentctl.dev/v1alpha1 +kind: Workflow +metadata: + name: portable-summary-openai + description: Opt-in OpenAI variant of the portable summary fixture. +spec: + outputs: + summary: "${{ tasks.summarize.output.text }}" + providers: + selected: + kind: openai + credential: + env: OPENAI_API_KEY + policy: + networkAllowlist: [api.openai.com] + agents: + summarizer: + provider: selected + model: gpt-5.6 + instructions: Return one short evidence summary. + maxTurns: 1 + maxToolCalls: 0 + maxOutputTokens: 64 + timeoutSeconds: 30 + reasoning: + effort: low + tasks: + - id: summarize + uses: agent:summarizer + with: + prompt: Summarize the supplied evidence. diff --git a/examples/docs/release-readiness/workflow.yaml b/examples/docs/release-readiness/workflow.yaml new file mode 100644 index 0000000..602c53c --- /dev/null +++ b/examples/docs/release-readiness/workflow.yaml @@ -0,0 +1,45 @@ +apiVersion: agentctl.dev/v1alpha1 +kind: Workflow +metadata: + name: release-readiness + description: Gate bounded analysis behind deterministic release evidence. +spec: + inputs: + testsPassed: true + securityScanPassed: true + outputs: + decision: "${{ tasks.analyze.output.text }}" + providers: + fake: + kind: fake + agents: + reviewer: + provider: fake + model: scripted + instructions: Summarize only the verified release evidence. + maxTurns: 1 + maxToolCalls: 0 + maxOutputTokens: 64 + timeoutSeconds: 5 + providerOptions: + finalText: RELEASE_EVIDENCE_REVIEWED + actions: + assert: + kind: builtin.assert + tasks: + - id: verify-tests + uses: action:assert + with: + that: "${{ inputs.testsPassed }}" + message: test gate failed + - id: verify-security + uses: action:assert + needs: [verify-tests] + with: + that: "${{ inputs.securityScanPassed }}" + message: security gate failed + - id: analyze + uses: agent:reviewer + needs: [verify-tests, verify-security] + with: + prompt: Summarize the verified test and security gates. diff --git a/examples/docs/scheduled-review/workflow.yaml b/examples/docs/scheduled-review/workflow.yaml new file mode 100644 index 0000000..5b7fbaa --- /dev/null +++ b/examples/docs/scheduled-review/workflow.yaml @@ -0,0 +1,32 @@ +apiVersion: agentctl.dev/v1alpha1 +kind: Workflow +metadata: + name: scheduled-operational-review + description: Produce a deterministic artifact for an external scheduler. +spec: + inputs: + reportPath: artifacts/operational-review.txt + status: healthy + outputs: + artifact: "${{ inputs.reportPath }}" + policy: + workspaceRoot: . + writableRoots: [artifacts] + approval: never + actions: + assert: + kind: builtin.assert + write: + kind: builtin.write + tasks: + - id: verify-status + uses: action:assert + with: + that: "${{ inputs.status == 'healthy' }}" + message: operational status is not healthy + - id: report + uses: action:write + needs: [verify-status] + with: + path: "${{ inputs.reportPath }}" + content: scheduled operational review passed diff --git a/examples/memory-flow/README.md b/examples/memory-flow/README.md index c7d38db..e1c757d 100644 --- a/examples/memory-flow/README.md +++ b/examples/memory-flow/README.md @@ -1,35 +1,5 @@ -# Memory Flow +# Memory Flow (legacy) -This example proves the two memory layers added to `agentctl`: +This directory is a migration fixture for the retired TypeScript playbook format. The current Rust CLI does not accept `mission.playbook.yaml`. -- `working` memory is checkpointed inside the runtime DB for the current run -- `longTerm` memory is stored separately and survives across runs - -Run it with: - -```bash -agentctl run examples/memory-flow/mission.playbook.yaml --db .runtime/memory-flow.db -``` - -What it does: - -1. seeds working memory with `service=checkout` -2. writes `finding=restore-drill-missing` into working memory -3. reads the working-memory value back -4. persists the same fact into long-term memory -5. searches the long-term store by exact key -6. asserts the search returned exactly one match -7. retrieves that long-term entry back into working memory as `memory.working.recalled` -8. verifies the promoted value matches the original finding - -Artifacts/state to inspect after the run: - -- runtime DB: `~/.agentctl/runtime/runtime.db` unless `--db` overrides it -- example runtime DB from the command above: `.runtime/memory-flow.db` -- long-term memory DB for this example: `examples/memory-flow/state/long-term.db` - -Expected outcome: - -- the run completes with `status: "succeeded"` -- `tasks.read_long_term.output.matchCount` is `1` -- `memory.working.recalled` is `restore-drill-missing` +Use [`../v1/working-memory.yaml`](../v1/working-memory.yaml) and [`../v1/long-term-memory.yaml`](../v1/long-term-memory.yaml) for supported examples. See [Memory](../../docs/MEMORY.md) for checkpoint, retention, and recovery behavior. diff --git a/examples/prompt-cache/README.md b/examples/prompt-cache/README.md index 814c77a..bd3f23e 100644 --- a/examples/prompt-cache/README.md +++ b/examples/prompt-cache/README.md @@ -1,39 +1,5 @@ -# Prompt Cache Example +# Prompt Cache Example (legacy) -This example uses a local mock OpenAI-compatible Responses endpoint to show provider-native prompt-cache behavior. +This directory is a migration fixture for the retired TypeScript playbook and CLI. Its mock server and `mission.playbook.yaml` are not a supported current workflow. -It proves: - -- playbook-level prompt cache config -- grouped multi-agent cache sharing -- deterministic task verification -- runtime cache metrics visible through `agentctl prompt-cache stats` - -## Run it - -Start the mock server in one terminal: - -```bash -node examples/prompt-cache/mock-openai-server.mjs -``` - -Then run the playbook in another: - -```bash -agentctl run examples/prompt-cache/mission.playbook.yaml --db .runtime/prompt-cache-example.db --api-key test-key -``` - -Inspect the cache metrics: - -```bash -agentctl prompt-cache stats --db .runtime/prompt-cache-example.db --verbose -``` - -Expected behavior: - -- the run succeeds -- the mock server prints the same `prompt_cache_key` for both agent requests -- the second response reports cached tokens -- `prompt-cache stats` shows: - - `totalResponses: 2` - - `hitResponses: 1` +The current API exposes prompt-cache capability and usage fields through provider configuration, durable provider records, and observability. Consult the generated schema and [provider capability matrix](../../docs/reference/MATRICES.md), then validate any new `agentctl.dev/v1alpha1` workflow with `agentctl check` before running it. diff --git a/examples/prompt-file-vars/README.md b/examples/prompt-file-vars/README.md index e865d9d..e74f296 100644 --- a/examples/prompt-file-vars/README.md +++ b/examples/prompt-file-vars/README.md @@ -1,28 +1,5 @@ -# Prompt File Vars Example +# Prompt File Variables (legacy) -This example proves: +This directory is a migration fixture for the retired TypeScript playbook format. The current Rust CLI does not accept `mission.playbook.yaml` or its prompt placeholder syntax. -- agent instructions can come from a file with `instructionsFile` -- task-scoped `vars` are the primary invocation surface for both agents and modules -- agent-level `vars` act as reusable defaults -- prompt placeholders can use bare names like `{{ service }}` or the alias form `{{ vars.severity }}` -- task vars can resolve dynamic values from prior task output at execution time - -Run it with: - -```bash -agentctl check examples/prompt-file-vars/mission.playbook.yaml -agentctl run examples/prompt-file-vars/mission.playbook.yaml --db .runtime/prompt-file-vars.db -``` - -Expected result: - -- `check` succeeds -- `project` proves module task templating with: - - `{{ service }}` - - `{{ vars.finding }}` -- `review` renders the prompt file with: - - `service: checkout` - - `finding: restore-drill-missing` - - `severity: medium` -- `verify` and `verify_project` pass deterministically +Use [`../v1/dataflow.yaml`](../v1/dataflow.yaml) for supported template and task-output examples. The [YAML reference](../../docs/reference/YAML.md) documents current expressions, variables, and instruction files. diff --git a/examples/real-autonomy/README.md b/examples/real-autonomy/README.md index 9a03795..85e8215 100644 --- a/examples/real-autonomy/README.md +++ b/examples/real-autonomy/README.md @@ -1,45 +1,5 @@ -# Real Autonomy Example +# Real Autonomy Example (legacy) -This example exercises a real model-backed autonomous run with `agentctl`. +This directory is a migration fixture for the retired TypeScript playbook format. The current Rust CLI does not accept `mission.playbook.yaml`. -The agent: - -- inspects a small service fixture under `./fixtures/service` -- decides which workspace read tools to use -- returns the final report Markdown -- has that report persisted to `./artifacts/ops-readiness-report.md` by a deterministic task -- passes a deterministic verification step that checks for required findings and concrete evidence from the fixture files - -## Requirements - -- `OPENAI_API_KEY` set in the environment, or `--api-key` passed to the CLI -- network access to the OpenAI Responses API - -## Run - -```bash -cd /Users/ompragash/Git/agentctl -npm link -agentctl run examples/real-autonomy/mission.playbook.yaml --db .runtime/real-autonomy.db -``` - -Or with a one-shot override: - -```bash -cd /Users/ompragash/Git/agentctl -npm link -agentctl run examples/real-autonomy/mission.playbook.yaml --db .runtime/real-autonomy.db --api-key "$OPENAI_API_KEY" -``` - -## Expected outcome - -The run should: - -- complete with `status: "succeeded"` -- create `examples/real-autonomy/artifacts/ops-readiness-report.md` -- mention the missing backup restore drill -- mention the missing documented on-call escalation policy -- cite `README.md` and `docs/runbook.md` -- quote the concrete evidence lines from those files - -The final verification task uses `set -eu`, so the run fails immediately if the artifact is missing, any required finding is absent, or the report is not grounded in the fixture evidence. +For a supported bounded-agent workflow, use [`../v1/fake-provider.yaml`](../v1/fake-provider.yaml) without a credential or [`../v1/openai-live.yaml`](../v1/openai-live.yaml) with `OPENAI_API_KEY`. See the [first agent workflow guide](../../docs/guides/FIRST_AGENT_WORKFLOW.md) for verified commands and expected output. diff --git a/examples/remote-mcp-autonomy/README.md b/examples/remote-mcp-autonomy/README.md index c5baa90..4d637ad 100644 --- a/examples/remote-mcp-autonomy/README.md +++ b/examples/remote-mcp-autonomy/README.md @@ -1,40 +1,5 @@ -# Remote MCP Autonomy Example +# Remote MCP Autonomy Example (legacy) -This example proves that `agentctl` can run autonomously across a real remote MCP boundary, not just local built-in tools. +This directory is a migration fixture for the retired TypeScript playbook and MCP server contract. The current Rust CLI does not accept `mission.playbook.yaml`, and the JavaScript mock is not part of current acceptance coverage. -The flow is: - -- a standalone MCP HTTP server listens on `http://127.0.0.1:43127/mcp` -- the agent calls `mcp:auditor/audit_service` -- the remote server reads the fixture and returns a report through MCP -- a deterministic task persists the report to `./artifacts/remote-mcp-report.md` -- a deterministic verification task checks the required findings - -## Run - -Start the MCP server in one terminal: - -```bash -cd /Users/ompragash/Git/agentctl -npm link -node examples/remote-mcp-autonomy/mock-mcp-server.mjs -``` - -Run the playbook in another terminal: - -```bash -cd /Users/ompragash/Git/agentctl -npm link -agentctl run examples/remote-mcp-autonomy/mission.playbook.yaml --db .runtime/remote-mcp-autonomy.db -``` - -## Expected outcome - -The run should: - -- complete with `status: "succeeded"` -- create `examples/remote-mcp-autonomy/artifacts/remote-mcp-report.md` -- mention the missing rollback validation drill -- mention the missing incident communication owner - -The verification task uses `set -eu`, so the run fails immediately if the artifact is missing or the report omits either finding. +Use [`../v1/mcp.yaml`](../v1/mcp.yaml) for the supported protocol workflow and [MCP integration](../../docs/MCP.md) for authentication, transport, capability, and failure semantics. diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 7e27eb7..4e29356 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -22,6 +22,7 @@ fn main() -> Result<()> { .to_path_buf(); match command.as_str() { "verify" => verify(&root), + "docs-verify" => docs_verify(&root), "acceptance" => acceptance::run(&root), "acceptance-container" => acceptance::container(&root), "acceptance-live-openai" => acceptance::live_openai(&root), @@ -33,7 +34,7 @@ fn main() -> Result<()> { } "help" | "--help" | "-h" => { println!( - "cargo xtask verify\ncargo xtask acceptance\ncargo xtask acceptance-container\ncargo xtask acceptance-live-openai\ncargo xtask generate\ncargo xtask package\ncargo xtask secret-scan" + "cargo xtask verify\ncargo xtask docs-verify\ncargo xtask acceptance\ncargo xtask acceptance-container\ncargo xtask acceptance-live-openai\ncargo xtask generate\ncargo xtask package\ncargo xtask secret-scan" ); Ok(()) } @@ -41,6 +42,29 @@ fn main() -> Result<()> { } } +fn docs_verify(root: &Path) -> Result<()> { + println!("[1/6] build documentation test binary"); + run(root, "cargo", &["build", "-p", "agentctl", "--locked"])?; + + println!("[2/6] generated CLI and schema freshness"); + verify_generated(root)?; + + println!("[3/6] canonical v1 examples"); + verify_examples(root)?; + + println!("[4/6] documentation journey examples"); + verify_docs_examples(root)?; + + println!("[5/6] public writing and source inclusion"); + verify_public_documentation(root)?; + + println!("[6/6] local Markdown links"); + verify_markdown_links(root)?; + + println!("agentctl documentation verification passed"); + Ok(()) +} + pub(crate) fn package(root: &Path) -> Result<()> { run( root, @@ -394,6 +418,230 @@ fn verify_examples(root: &Path) -> Result<()> { Ok(()) } +fn verify_docs_examples(root: &Path) -> Result<()> { + let binary = binary_path(root); + let examples = root.join("examples/docs"); + let mut files = Vec::new(); + collect_files(&examples, &mut files)?; + files.sort(); + + for path in files + .iter() + .filter(|path| path.extension() == Some(OsStr::new("yaml"))) + { + let mut command = Command::new(&binary); + command.arg("check").arg(path).args(["--output", "json"]); + let output = bounded_output(command, "agentctl documentation example check") + .with_context(|| format!("check documentation example {}", path.display()))?; + ensure_success(&output, &format!("check {}", path.display()))?; + } + + for (directory, expected) in [ + ("release-readiness", "RELEASE_EVIDENCE_REVIEWED"), + ("scheduled-review", "operational-review.txt"), + ("ci-quality-gate", "\"verdict\":\"pass\""), + ("provider-portability", "PORTABLE_SUMMARY_VERIFIED"), + ] { + let source_name = if directory == "provider-portability" { + "fake.yaml" + } else { + "workflow.yaml" + }; + let temporary = tempfile::tempdir()?; + fs::create_dir_all(temporary.path().join("artifacts"))?; + fs::copy( + examples.join(directory).join(source_name), + temporary.path().join("workflow.yaml"), + )?; + let mut command = Command::new(&binary); + command.current_dir(temporary.path()).args([ + "run", + "workflow.yaml", + "--db", + "runtime.db", + "--output", + "json", + ]); + let output = bounded_output(command, "agentctl documentation example run") + .with_context(|| format!("run documentation example {directory}"))?; + ensure_success(&output, &format!("run documentation example {directory}"))?; + let stdout = String::from_utf8_lossy(&output.stdout); + if !stdout.contains(expected) && !temporary.path().join("artifacts").join(expected).exists() + { + bail!("documentation example `{directory}` did not produce `{expected}`"); + } + } + + let temporary = tempfile::tempdir()?; + fs::copy( + examples.join("ci-quality-gate/workflow.yaml"), + temporary.path().join("workflow.yaml"), + )?; + let mut failed_gate = Command::new(&binary); + failed_gate.current_dir(temporary.path()).args([ + "run", + "workflow.yaml", + "--db", + "runtime.db", + "--input", + "checksPassed=false", + "--output", + "json", + ]); + let output = bounded_output(failed_gate, "agentctl failed documentation quality gate")?; + if output.status.code() != Some(4) { + bail!( + "failed documentation quality gate returned {:?}: {}", + output.status.code(), + output_diagnostics(&output) + ); + } + Ok(()) +} + +fn public_documentation_files(root: &Path) -> Result> { + let mut files = vec![ + root.join("README.md"), + root.join("CODE_OF_CONDUCT.md"), + root.join("SECURITY.md"), + root.join("examples/docs/README.md"), + ]; + let mut docs = Vec::new(); + collect_files(&root.join("docs"), &mut docs)?; + files.extend(docs.into_iter().filter(|path| { + path.extension() == Some(OsStr::new("md")) + && !path.components().any(|component| { + matches!( + component.as_os_str().to_str(), + Some("execution" | "research") + ) + }) + })); + files.sort(); + files.dedup(); + Ok(files) +} + +fn verify_public_documentation(root: &Path) -> Result<()> { + let required = [ + "docs/guides/INSTALLATION.md", + "docs/guides/GETTING_STARTED.md", + "docs/guides/FIRST_AGENT_WORKFLOW.md", + "docs/guides/WORKFLOW_AUTHORING.md", + "docs/guides/LOCAL_OPERATION.md", + "docs/guides/CI_CD.md", + "docs/guides/TROUBLESHOOTING.md", + "docs/reference/YAML.md", + "docs/reference/CLI_OUTPUT.md", + "docs/reference/ENVIRONMENT_AND_PATHS.md", + "docs/reference/MATRICES.md", + "docs/reference/DATABASE.md", + "docs/reference/TERMINOLOGY.md", + "docs/architecture/DIAGRAMS.md", + "docs/development/REPOSITORY.md", + "docs/development/ADD_ACTION.md", + "docs/development/ADD_PROVIDER.md", + "docs/development/ADD_MIGRATION.md", + "docs/development/DOCUMENTATION.md", + ]; + for relative in required { + if !root.join(relative).is_file() { + bail!("required canonical documentation is missing: {relative}"); + } + } + + let discouraged = [ + "unlock", + "unleash", + "revolutionize", + "supercharge", + "seamlessly", + "effortlessly", + "cutting-edge", + "game-changing", + "next-generation", + "robust and scalable", + "powerful solution", + "in today's fast-paced world", + ]; + for path in public_documentation_files(root)? { + let source = fs::read_to_string(&path)?; + if source.contains('—') { + bail!("em dash in public documentation: {}", path.display()); + } + if source.contains("/Users/") { + bail!( + "absolute local path in public documentation: {}", + path.display() + ); + } + let lower = source.to_lowercase(); + if let Some(phrase) = discouraged.iter().find(|phrase| lower.contains(**phrase)) { + bail!( + "discouraged marketing phrase `{phrase}` in {}", + path.display() + ); + } + for line in source.lines() { + let Some(include) = line + .trim() + .strip_prefix("")) + else { + continue; + }; + let relative = include + .split_whitespace() + .next() + .context("documentation include requires a source path")?; + if !root.join(relative).is_file() { + bail!( + "documentation include in {} references missing `{relative}`", + path.display() + ); + } + } + } + Ok(()) +} + +fn verify_markdown_links(root: &Path) -> Result<()> { + for path in public_documentation_files(root)? { + let source = fs::read_to_string(&path)?; + let mut remaining = source.as_str(); + while let Some(start) = remaining.find("](") { + remaining = &remaining[start + 2..]; + let Some(end) = remaining.find(')') else { + bail!("unterminated Markdown link in {}", path.display()); + }; + let destination = &remaining[..end]; + remaining = &remaining[end + 1..]; + if destination.is_empty() + || destination.starts_with('#') + || destination.starts_with('/') + || destination.starts_with("http://") + || destination.starts_with("https://") + || destination.starts_with("mailto:") + { + continue; + } + let local = destination + .split('#') + .next() + .context("Markdown destination")?; + let resolved = path.parent().context("Markdown source parent")?.join(local); + if !resolved.exists() { + bail!( + "broken local link in {}: `{destination}` resolves to {}", + path.display(), + resolved.display() + ); + } + } + } + Ok(()) +} + fn verify_metadata(root: &Path) -> Result<()> { let mut metadata = Command::new("cargo"); metadata From 3fcd4bc7394975d923773141eb139324494d4f9a Mon Sep 17 00:00:00 2001 From: Ompragash Date: Thu, 23 Jul 2026 10:39:42 +0530 Subject: [PATCH 2/2] docs: fix case-sensitive policies link --- docs/reference/YAML.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/YAML.md b/docs/reference/YAML.md index 381acbf..3e3b0c4 100644 --- a/docs/reference/YAML.md +++ b/docs/reference/YAML.md @@ -105,4 +105,4 @@ agentctl plan examples/v1/dataflow.yaml agentctl run examples/v1/dataflow.yaml --db /tmp/dataflow.db --output json --color never ``` -Related guides: [Workflow authoring](../guides/WORKFLOW_AUTHORING.md), [Policies](../POLICIES.md), [Tools](../TOOLS.md), and [Workflow DSL](../DSL.md). +Related guides: [Workflow authoring](../guides/WORKFLOW_AUTHORING.md), [Policies](../policies.md), [Tools](../TOOLS.md), and [Workflow DSL](../DSL.md).