Skip to main content

Compile a declarative DAG of subagents into an orchestrated team on AWS Bedrock AgentCore.

Project description

Concursus

License: MIT Python 3.10+

Compile a declarative DAG of subagents into a deployed, orchestrated team on AWS Bedrock AgentCore.

Concursus (Latin "a running-together / convergence") is cursus's agent-orchestration sibling. Where cursus compiles a pipeline DAG + configs into a SageMaker pipeline, Concursus compiles an AgentDAG + per-agent .agent.yaml manifests into (1) an AgentCore provisioning plan — one CreateAgentRuntime per agent — and (2) a supervisor that dispatches the agents in topological order, wires each agent's declared output into its dependents' input, and routes shared state through AgentCore Memory.

It is the coordinator AgentCore deliberately doesn't ship: AgentCore gives you transport (A2A), tool discovery (Gateway), microVM isolation, identity, memory, and hosting — but no scheduler, dependency graph, or supervisor. You declare a DAG of agents; Concursus provisions them and runs them.

Status: alpha. This release ships the declarative core (AgentDAG + AgentManifest) and the offline compiler: the dependency resolver, the runtime builder, the OrchestrationAssembler (DAG + manifests → a ProvisioningPlan), and the topological Supervisor — plus the plan / deploy / run CLI verbs. The compiler is pure-Python; boto3 stays behind the [agentcore] extra and is imported lazily only when deploy --execute / run --execute actually calls AWS.


Installation

pip install concursus                 # declarative core (pure Python)
pip install "concursus[agentcore]"    # + the AWS Bedrock AgentCore runtime binding (roadmap)

Requires Python 3.10+.

Quick start

Declare a team as an AgentDAG (nodes = agents, edges = data dependencies):

from concursus import AgentDAG

dag = AgentDAG()
for agent in ["ingest", "summarize", "critique", "format"]:
    dag.add_node(agent)
dag.add_edge("ingest", "summarize")
dag.add_edge("summarize", "critique")
dag.add_edge("critique", "format")

dag.topological_sort()   # ['ingest', 'summarize', 'critique', 'format']  <- dispatch order
dag.validate()           # raises if the topology has a cycle

Describe each agent with an .agent.yaml manifest — its AgentCore binding + typed interface:

# summarize.agent.yaml
registry:
  container_uri: 111122223333.dkr.ecr.us-east-1.amazonaws.com/summarize-agent:latest
  role_arn: arn:aws:iam::111122223333:role/ConcursusAgentRuntimeRole
  network_mode: PUBLIC       # or VPC
  protocol: HTTP             # HTTP (/invocations) | MCP (/mcp) | A2A (/)
  qualifier: DEFAULT
  # ...or reuse an already-deployed agent:
  # agent_runtime_arn: arn:aws:bedrock-agentcore:us-east-1:111122223333:runtime/summarize-xyz
contract:
  inputs:
    document: {type: string}
  outputs:                   # required — the dependency resolver's type gate
    summary: {type: string}
    key_points: {type: array, items: {type: string}}
spec:
  depends_on:
    - {from: ingest.document, to: document}
from concursus import AgentManifest

m = AgentManifest.from_yaml("summarize.agent.yaml").validate()
m.protocol        # 'HTTP'
m.output_schema   # {'summary': {...}, 'key_points': {...}}

Or from the CLI:

concursus info                        # overview
concursus validate *.agent.yaml       # validate manifests
concursus --version

Compile a plan (plandeployrun)

Point the compiler at your manifests. Edges are inferred from each manifest's depends_on (or pass --dag ingest->summarize to set them explicitly). plan prints a JSON ProvisioningPlan — a topological order, one create_agent_runtime entry per agent, and the resolved producer→consumer wiring — without touching AWS:

concursus plan *.agent.yaml
from concursus import AgentDAG, AgentManifest, OrchestrationAssembler, Supervisor

manifests = {m.name: m for m in map(AgentManifest.from_yaml, paths)}
dag = AgentDAG()
for name in manifests:
    dag.add_node(name)
dag.add_edge("ingest", "summarize").add_edge("summarize", "critique")

plan = OrchestrationAssembler(account="111122223333", region="us-east-1").assemble(dag, manifests)
plan.order           # ['ingest', 'summarize', 'critique']  <- dispatch order
plan.to_dict()       # JSON-serializable preview (what `concursus plan` prints)

deploy dry-runs what would be created (nothing imported); --execute provisions each agent end-to-end — ensure its IAM execution role, build + push its image to ECR (when the plan carries a placeholder URI), then CreateAgentRuntime — reusing an existing image or runtime ARN as-is. run dry-runs the topological dispatch; --execute invokes the live runtimes, threading each output into its dependents:

concursus deploy *.agent.yaml                          # dry-run: the role/image/create steps
concursus deploy *.agent.yaml --execute --source-dir . # + boto3 + docker: role → ECR image → create
concursus run    *.agent.yaml --inputs '{"uri": "s3://doc"}'            # dry-run the dispatch
concursus run    *.agent.yaml --inputs @inputs.json --execute          # live InvokeAgentRuntime
outputs = Supervisor(plan, manifests).run({"uri": "s3://doc"})   # {node_id: output_dict}

How it works (the compile target)

Concursus compiles AgentDAG + manifests through validate → resolve → provision → assemble, mapping cursus concepts onto AgentCore primitives:

cursus Concursus AgentCore primitive
PipelineDAG AgentDAG dispatch order (topological)
.step.yaml .agent.yaml manifest container image + roleArn + protocol
DependencyType enum output JSON Schema (mandatory) the resolver's type gate
PropertyReference (deferred) AgentRef (eager JSONPath) InvokeAgentRuntime response
step registration agent registration CreateAgentRuntime → ARN + V1 + DEFAULT endpoint
PipelineAssemblerPipeline OrchestrationAssembler → supervisor + plan BedrockAgentCoreApp supervisor
S3 artifact channels shared run state AgentCore Memory

The supervisor dispatches agents in topological order, invokes each with InvokeAgentRuntime under one runtimeSessionId (session affinity → warm microVMs), extracts each producer's output by JSONPath and injects it into its consumers, and persists outputs to Memory so state survives the ephemeral microVMs.

Roadmap

  • Declarative core: AgentDAG + AgentManifest (.agent.yaml) + validation + CLI
  • Dependency resolver over declared output JSON Schemas (AgentRef wiring + type-gating)
  • OrchestrationAssembler: emit an AgentCore provisioning plan (CreateAgentRuntime per agent + synthesized IAM roles + endpoints)
  • The supervisor: topological dispatch over InvokeAgentRuntime with AgentRef wiring + one stable runtimeSessionId
  • plan / deploy / run CLI verbs (deploy/run --execute bind boto3 lazily)
  • Memory-backed shared run state (persist outputs across the ephemeral microVMs)
  • Gateway/A2A node types; a data-driven catalog + recommender of team topologies

License

MIT © Tianpei Xie

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

concursus-0.3.0.tar.gz (39.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

concursus-0.3.0-py3-none-any.whl (32.2 kB view details)

Uploaded Python 3

File details

Details for the file concursus-0.3.0.tar.gz.

File metadata

  • Download URL: concursus-0.3.0.tar.gz
  • Upload date:
  • Size: 39.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.7

File hashes

Hashes for concursus-0.3.0.tar.gz
Algorithm Hash digest
SHA256 c1ea70fd284edcac9759998fb7706e1336738195a2c1cc7a0eaafaa2ee6fd8f4
MD5 57f35f79551fbc14b9c8a5796200105c
BLAKE2b-256 6db0607c50edf7e4d5b2eb2f21f4b787ce7e9e81c7c255efd5c2f0768a0fb943

See more details on using hashes here.

File details

Details for the file concursus-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: concursus-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 32.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.7

File hashes

Hashes for concursus-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8733b7bc213ff87e1b2d5d62cdb37130ea22a8a81018d8f094aca5e5b041f576
MD5 5ceef593405d71d4f7eb5bccf382eeca
BLAKE2b-256 a933a0b18bb8638c04913709d5d67eea3fada81e0be34132c5b88ac8b47b47a6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page