Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
44b540e
docs(automations): record Coven Automations v1 program status (coven#…
CompleteDotTech Aug 30, 2026
fb302f2
docs: plan cryptographic fresh-user and biometric assurance proofs (c…
CompleteDotTech Aug 30, 2026
fcc026c
docs: operationalize Coven Automations v1 tracker roadmap and drift c…
CompleteDotTech Aug 30, 2026
957715f
docs: consolidate Coven security policy, threat boundary, and support…
CompleteDotTech Aug 30, 2026
9847960
docs(pairing): plan TUI QR bootstrap and E2EE mobile pairing (refs #7…
CompleteDotTech Aug 30, 2026
d07bf61
docs: remove duplicate local public documentation (#870)
CompleteDotTech Aug 30, 2026
a781c9e
docs(807): record shipped reliability scorecard status decision (#863)
CompleteDotTech Aug 30, 2026
c703693
docs: record issue 670 docs program status on main
CompleteDotTech Aug 30, 2026
753f4bb
fix(agents): enforce target input-guardrail parity across handoffs
CompleteDotTech Aug 30, 2026
ba3a154
docs(cli): document the deterministic JSON help contract (#868)
CompleteDotTech Aug 30, 2026
c4c9ccb
docs(automations): specify coven.automations.v1 schemas, state machin…
CompleteDotTech Aug 30, 2026
39feb6d
refactor: extract route/version authority gate from coven-cli api
CompleteDotTech Aug 30, 2026
564b4f0
feat(agents): add invocation identity and canonical invocation events
CompleteDotTech Aug 30, 2026
b40c581
fix(agents): order AgentRef revision display and apply rustfmt output
CompleteDotTech Aug 30, 2026
28e1394
fix(agents): box the error inside RunFailure for the clippy size budget
CompleteDotTech Aug 30, 2026
23a1e40
fix: match boxed agent failures in tests
CompleteDotTech Aug 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
756 changes: 33 additions & 723 deletions README.md

Large diffs are not rendered by default.

319 changes: 215 additions & 104 deletions SECURITY.md

Large diffs are not rendered by default.

25 changes: 23 additions & 2 deletions crates/coven-agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,22 @@ from session history. Results correlate to calls by id, so the runner rejects a
response that reuses one before running any tool in that response, with
`RunError::DuplicateToolCallId`.

Every run carries one stable `InvocationId` from its `InvocationStarted` event
through its terminal event. Callers pin the identity through
`RunOptions::invocation_id`; when they do not, the runner generates a
process-scoped one that is not durable across restarts. Nested work correlates
to its parent through `RunOptions::parent_invocation`, so observers can
reconstruct parent/child relationships without parsing model prose. The
canonical `InvocationEvent` stream, delivered to an `InvocationObserver`,
reports the validated `AgentRef` target (with an optional revision pin) at
start, the agent that completed or failed at the terminal event, and the
invocation's `RunFailureKind` on failure. The legacy pointer-swap handoff is
reported as `ControlTransferred`: it moves control inside one invocation and is
not durable A2A delegation — an explicit delegation contract replaces it in a
later slice. The `RunObserver` stream remains unchanged during migration and
will be folded into the canonical events; `Runner::run` remains the
compatibility facade while that migration is incomplete.

`GoalLoopRunner` composes the single-run `Runner` into a bounded
`loop-until-done` primitive. An injected `LoopEvaluator` decides whether each
result satisfies the goal or supplies the next input, while an injected
Expand All @@ -43,8 +59,13 @@ does not own SQLite, daemon scheduling, GitHub labels, or UI state.

The crate deliberately does not include an OpenAI client, a daemon command,
MCP, sandbox execution, voice, or realtime transport. Those are adapters and
application concerns. Keeping this crate as a workspace leaf also allows it to
move into its own repository if the API stabilizes.
application concerns. This crate is Coven's agent behavior/execution component:
it owns the one-agent model/tool/policy loop. Invocation and delegation
ownership belongs to the Psyche orchestration contracts, process and harness
execution to the Coven daemon, and remote placement to the existing Coven hub.
It must not grow into a second distributed A2A runtime. Keeping this crate as a
workspace leaf also allows it to move into its own repository if the API
stabilizes.

The implementation was derived from public behavioral documentation and
OpenCoven's existing runtime requirements, not from another SDK's source code.
Expand Down
27 changes: 21 additions & 6 deletions crates/coven-agents/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use thiserror::Error;

use crate::{AgentId, RunItem};
use crate::{AgentId, InvocationId, RunItem};

pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;

Expand Down Expand Up @@ -35,6 +35,13 @@ pub enum ConfigError {
handoff: String,
target: AgentId,
},
#[error("invocation id {reason}")]
InvalidInvocationId { reason: &'static str },
#[error("agent reference {component} {reason}")]
InvalidAgentRef {
component: &'static str,
reason: &'static str,
},
}

#[derive(Debug, Error)]
Expand Down Expand Up @@ -105,9 +112,16 @@ pub enum RunError {
/// The runner never writes `new_items` to the session store on failure, so a
/// failed run cannot silently become durable history. Persisting a partial
/// transcript is a deliberate caller decision.
///
/// The wrapped error is boxed to keep `RunFailure` small: the runner returns
/// it by value on every failure path, and the workspace clippy policy rejects
/// `Err` variants larger than 128 bytes.
#[derive(Debug)]
pub struct RunFailure {
pub error: RunError,
/// The stable invocation identity of the failed run, matching the identity
/// carried by its invocation events.
pub invocation: InvocationId,
pub error: Box<RunError>,
/// Items produced during this run before it failed, in order. Always begins
/// with the user message that started the run.
pub new_items: Vec<RunItem>,
Expand All @@ -121,19 +135,19 @@ pub struct RunFailure {
impl RunFailure {
/// Discards the partial transcript and keeps only the error.
pub fn into_error(self) -> RunError {
self.error
*self.error
}
}

impl std::fmt::Display for RunFailure {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.error, formatter)
std::fmt::Display::fmt(self.error.as_ref(), formatter)
}
}

impl std::error::Error for RunFailure {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.error)
Some(self.error.as_ref())
}
}

Expand All @@ -144,7 +158,8 @@ mod tests {
#[test]
fn run_failure_exposes_the_wrapped_error_as_its_source() {
let failure = RunFailure {
error: RunError::SessionUnavailable,
invocation: InvocationId::try_new("inv-test").unwrap(),
error: Box::new(RunError::SessionUnavailable),
new_items: Vec::new(),
turns: 0,
handoffs: 0,
Expand Down
10 changes: 8 additions & 2 deletions crates/coven-agents/src/guardrail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@ impl GuardrailVerdict {
}

#[async_trait]
/// Checks the original user input before the starting agent runs.
/// Checks the bounded ingress of an agent before its first model turn.
///
/// Input guardrails attached only to handoff targets do not run in this MVP.
/// The runner evaluates the starting agent's input guardrails against the
/// original user input before the run begins, and a handoff target's input
/// guardrails against the same original user input before the target's first
/// model turn, so entering an agent through a handoff cannot grant access that
/// direct entry would reject. Input guardrails never inspect a serialized
/// transcript; the structured task/context manifest for delegated invocations
/// is a separate contract (see OpenCoven/coven#804).
pub trait InputGuardrail<C>: Send + Sync
where
C: Sync,
Expand Down
Loading
Loading