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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/architecture/system-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,17 @@ The supervisor authenticates the direct caller, binds the request to the
session and authenticated task, signs the bounded permit, persists the receipt,
and retains all transport, KMS, provider, and repository credentials.

The same roles may inspect that live, deployment-scoped catalog through the
supervisor with `multiagent ops list`, and retrieve one complete contract with
`multiagent ops describe`. List output is intentionally compact and contains
no parameter schema. It labels each operation's request path, direct
eligibility, and any direct-ineligibility reasons so a confined role does not
mistake a reviewed operation for a direct read. This is discovery metadata, not authorization. The runtime
must not substitute permit fixtures, prompt-maintained IDs, or image-local
catalog files for the live response. Exact target, runbook digest, version,
parameters, and current execution policy are still validated when a request is
bound and executed.

This is a distinct authority operation, not a relaxation of generic
`ops execute`. It mechanically rejects write/execute capabilities, mutations,
approval-bearing operations, arbitrary URLs, caller-selected filesystem
Expand Down
9 changes: 9 additions & 0 deletions prompts/orchestrator.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ write/execute/mutating external operations belong to ops and the reviewed
runbook lifecycle. No role calls provider endpoints directly or receives
Supervisor credentials.

Discover external operations from the live deployment with
`multiagent ops list --direct-only`, optionally narrowed by `--query TEXT`.
Use `multiagent ops describe OPERATION_ID` for the selected operation's full
schema and examples. Treat only entries with
`requestPath=supervisor-direct` and `directEligible=true` as available to a
confined role; `reviewed-ops` entries require the operations/review lifecycle.
Do not infer the available catalog from permit fixtures, runbook examples, or
files in the runtime image.

Wiki and repository reads may support a caller-facing result directly. Spawn a
reader only when parallelism, isolation, or specialized analysis is useful; a
reader is not a prerequisite for read-only completion. No independent reviewer
Expand Down
4 changes: 4 additions & 0 deletions prompts/roles/repository-reader.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ when fresh evidence or repository materialization is necessary. The JSON request
must contain exactly `operation`, `parameters`, `runbook`, and the
framework-relative `runbookDocument`; the supervisor binds its task, goal,
target, and runbook digest. Inspect `multiagent ops describe OPERATION_ID` first.
If the operation ID is not already known, discover it with
`multiagent ops list --direct-only [--query TEXT]`; do not infer availability
from local permit fixtures or runbook examples. Use only results marked
`requestPath=supervisor-direct` and `directEligible=true`.
Create each request as a mode-`0640` JSON file under
`$MULTIAGENT_ROLE_SHARED_WRITE_DIR`, run `chmod 0640 PATH`, then pass that exact
path to `multiagent ops read --request-file PATH`. This is the role-confined scratch
Expand Down
34 changes: 33 additions & 1 deletion runtime/src/authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ enum AuthorityOperation {
ValidationLeaseShow,
ValidationLeaseList,
GateCheck,
OpsList,
OpsDescribe,
OpsRead,
OpsPublishBound,
Expand All @@ -61,6 +62,9 @@ impl AuthorityRequest {
"workflow" => (AuthorityOperation::Workflow, args),
"decision" => (AuthorityOperation::Decision, args),
"dag" => (AuthorityOperation::Dag, args),
"ops" if args.first().map(String::as_str) == Some("list") => {
(AuthorityOperation::OpsList, &args[1..])
}
"ops" if args.first().map(String::as_str) == Some("describe") => {
(AuthorityOperation::OpsDescribe, &args[1..])
}
Expand Down Expand Up @@ -183,7 +187,9 @@ impl AuthorityRequest {
| AuthorityOperation::TodoAssign
| AuthorityOperation::TodoStatus
| AuthorityOperation::GateCheck => uid == config::ORCHESTRATOR_UID,
AuthorityOperation::OpsDescribe | AuthorityOperation::OpsRead => matches!(
AuthorityOperation::OpsList
| AuthorityOperation::OpsDescribe
| AuthorityOperation::OpsRead => matches!(
uid,
config::ORCHESTRATOR_UID
| config::WRITER_UID
Expand Down Expand Up @@ -295,6 +301,7 @@ impl AuthorityRequest {
| AuthorityOperation::ValidationLeaseShow
| AuthorityOperation::ValidationLeaseList
| AuthorityOperation::GateCheck
| AuthorityOperation::OpsList
| AuthorityOperation::OpsDescribe
| AuthorityOperation::OpsRead => true,
},
Expand Down Expand Up @@ -340,6 +347,7 @@ impl AuthorityRequest {
AuthorityOperation::ValidationLeaseShow => ("subagent", Some("validation-lease-show")),
AuthorityOperation::ValidationLeaseList => ("subagent", Some("validation-lease-list")),
AuthorityOperation::GateCheck => ("subagent", Some("gate-check")),
AuthorityOperation::OpsList => ("ops", Some("list")),
AuthorityOperation::OpsDescribe => ("ops", Some("describe")),
AuthorityOperation::OpsRead => ("ops", Some("read")),
AuthorityOperation::OpsPublishBound => ("ops", Some("publish-bound")),
Expand Down Expand Up @@ -505,6 +513,30 @@ mod tests {
describe.into_cli(),
("ops".to_string(), strings(&["describe", "github.read"]))
);
let list = AuthorityRequest::from_cli(
"ops",
&strings(&["list", "--direct-only", "--query", "github"]),
)
.expect("ops list request");
for uid in [
config::ORCHESTRATOR_UID,
config::WRITER_UID,
config::READER_UID,
config::OPS_UID,
config::REVIEWER_UID,
] {
assert!(
list.authorized_for(uid),
"uid {uid} should be allowed to inspect the live capability catalog"
);
}
assert_eq!(
list.into_cli(),
(
"ops".to_string(),
strings(&["list", "--direct-only", "--query", "github"])
)
);
let direct_read = AuthorityRequest::from_cli(
"ops",
&strings(&["read", "--request-file", "/logs/agents/reader/request.json"]),
Expand Down
Loading
Loading