Edges¶
Edges are the typed relationships between agents in a Claw society graph. They are first-class primitives -- not configuration, not metadata, not an afterthought. An edge determines what each agent can see, how events are routed between them, how conflicts are resolved, and when the interaction terminates.
In Claw SDK, the graph IS the program. Edges encode the semantics of collaboration.
What Is an Edge¶
An edge connects two or more agents and carries a type that defines concrete runtime behavior:
- Visibility -- which artifacts and events each agent can see.
- Event routing -- how messages flow between connected agents. Events travel along edges, not via global broadcast.
- Conflict resolution -- how competing or contradictory outputs are reconciled.
- Termination -- when the interaction along this edge is considered complete.
Every edge has a source and target (for binary edges) or a set of members (for group edges). The edge type -- Delegation, Oversight, Cooperation, Competition, or Coopetition -- determines the rules.
from claw import Society, Agent, Oversight
s = Society("code-review")
coder = Agent("coder", role="implementer", model="claude-sonnet")
reviewer = Agent("reviewer", role="critic", model="claude-sonnet")
# This edge IS the review relationship -- not just a link
s.connect(coder, reviewer, Oversight(max_rounds=3))
Agents referenced in connect() are automatically added to the society if not already present.
The Five Edge Types¶
Claw ships five built-in edge types, based on the collaboration taxonomy from Tran et al. (2025). Each type maps to a distinct pattern of multi-agent interaction.
Delegation¶
Task assignment from a delegator to a worker.
The delegator issues a task specification and instructions. The worker has full visibility into both. The delegator sees a progress summary. The interaction terminates when the worker reports complete or the delegator sends accept or reject.
Use Delegation when one agent is responsible for defining what needs to happen and another is responsible for doing it.
from claw import Society, Agent, Delegation
s = Society("task-pipeline")
pm = Agent("pm", role="project-manager", model="claude-sonnet")
coder = Agent("coder", role="implementer", model="claude-opus")
s.connect(pm, coder, Delegation())
Key configuration:
| Field | Type | Default | Description |
|---|---|---|---|
escalation_policy |
EscalationPolicy \| None |
None |
Policy for escalating issues during delegation |
from claw import Delegation, EscalationPolicy
s.connect(pm, coder, Delegation(
escalation_policy=EscalationPolicy(to="tech-lead"),
))
Visibility rules: - Worker sees: full task spec, delegator instructions, shared artifacts - Delegator sees: progress summary
Termination:
- Worker reports complete
- Delegator sends accept or reject
- max_rounds exceeded (if configured)
Oversight¶
Asymmetric review relationship.
The overseer has full visibility -- they see all artifacts and the overseen agent's work log. The overseen agent sees only feedback comments. The overseer adjudicates quality by approving or rejecting.
Use Oversight for code review, quality gates, editorial review, or any scenario where one agent evaluates another's output.
from claw import Society, Agent, Oversight
s = Society("review-gate")
coder = Agent("coder", role="implementer", model="claude-opus")
reviewer = Agent("reviewer", role="critic", model="claude-sonnet")
s.connect(coder, reviewer, Oversight(max_rounds=3))
Key configuration:
| Field | Type | Default | Description |
|---|---|---|---|
max_rounds |
int \| None |
None |
Maximum review rounds before forced termination |
on_deadlock |
EscalationPolicy \| Escalate \| None |
None |
What happens when max_rounds is reached without resolution |
from claw import Oversight, EscalationPolicy
from claw.resolve import Escalate
s.connect(coder, reviewer, Oversight(
max_rounds=3,
on_deadlock=Escalate(to="tech-lead"),
))
Visibility rules: - Overseer sees: all artifacts, overseen agent's work log - Overseen agent sees: only feedback comments from the overseer
Termination:
- Overseer sends approve or reject
- max_rounds exceeded
Cooperation¶
Bidirectional transparent collaboration toward a shared goal.
Both agents have full visibility into all shared artifacts and each other's work log. Outputs are merged into the shared artifacts. Neither agent has an information advantage.
Use Cooperation for pair programming, co-authoring, joint design, or any scenario where agents work together as equals.
from claw import Society, Agent, Cooperation
s = Society("pair-programming")
frontend = Agent("frontend", role="frontend-dev", model="claude-sonnet")
backend = Agent("backend", role="backend-dev", model="claude-sonnet")
s.connect(frontend, backend, Cooperation(shared=["api-contract"]))
Key configuration:
| Field | Type | Default | Description |
|---|---|---|---|
shared |
list[str] |
[] |
List of shared resource/topic identifiers that both agents have full visibility into |
Visibility rules: - Both agents see: all shared artifacts, each other's work log - Fully symmetric -- no information asymmetry
Termination:
- Both agents agree on completion
- max_rounds exceeded (if configured)
Competition¶
Independent work with judge-based selection of the best output.
Competing agents are isolated -- they can see the task specification but not each other's work. A resolution strategy selects the winner after all agents submit.
Use Competition for competitive coding, A/B testing of approaches, red team/blue team exercises, or any scenario where you want diverse solutions evaluated against each other.
from claw import Society, Agent, Competition, JudgePicks
s = Society("competitive-coding")
coder1 = Agent("coder1", role="implementer", model="claude-opus")
coder2 = Agent("coder2", role="implementer", model="claude-opus")
coder3 = Agent("coder3", role="implementer", model="claude-sonnet")
reviewer = Agent("reviewer", role="evaluator", model="claude-sonnet")
s.compete(
[coder1, coder2, coder3],
Competition(resolve=JudgePicks(judge=reviewer)),
)
Key configuration:
| Field | Type | Default | Description |
|---|---|---|---|
resolve |
ResolveStrategy |
(required) | Strategy for selecting the winning submission. Competition edges without a resolve strategy are rejected at compile time. |
Visibility rules:
- Each competitor sees: task specification only
- Competitors cannot see each other's work
- Judge (if JudgePicks) sees: all submissions
Termination:
- All competitors submit, then the resolution strategy runs
- max_rounds exceeded (if configured)
Coopetition¶
Mixed cooperation and competition on different aspects.
Agents cooperate on shared interests (full visibility) and compete on conflicting interests (isolated). Resolution is domain-specific and applied only to the competitive aspects.
Use Coopetition for negotiation, standards development, cross-team integration, or any scenario where agents share some goals but compete on others.
from claw import Society, Agent, Coopetition, MajorityVote
s = Society("api-negotiation")
team_a = Agent("team-a", role="api-designer", model="claude-sonnet")
team_b = Agent("team-b", role="api-designer", model="claude-sonnet")
s.negotiate(
[team_a, team_b],
Coopetition(
cooperate_on=["shared-api"],
compete_on=["implementation"],
resolve=MajorityVote(),
),
)
Key configuration:
| Field | Type | Default | Description |
|---|---|---|---|
cooperate_on |
list[str] |
[] |
Aspects where agents share information freely |
compete_on |
list[str] |
[] |
Aspects where agents work independently |
resolve |
ResolveStrategy |
(required) | Strategy for resolving competitive aspects |
Visibility rules:
- On cooperate_on topics: full mutual visibility (like Cooperation)
- On compete_on topics: isolated (like Competition)
Termination:
- Cooperative aspects reach agreement, competitive aspects are resolved
- max_rounds exceeded (if configured)
Group Edges¶
Some edge types have natural N-ary semantics -- they connect more than two agents at once. Claw calls these group edges (or hyperedges).
Three edge types support group semantics:
| Edge Type | Group Method | Example |
|---|---|---|
Competition |
society.compete() |
Tournament with N entrants |
Cooperation |
society.cooperate() |
N agents sharing an artifact |
Coopetition |
society.negotiate() |
Multi-party negotiation |
Two edge types are binary only:
| Edge Type | Method | Why |
|---|---|---|
Delegation |
society.connect() |
Task assignment is inherently one-to-one |
Oversight |
society.connect() |
Review is inherently between overseer and overseen |
Using group edges¶
Group edges require at least 2 members. Members must be unique (no duplicates). All member agents are automatically added to the society.
from claw import Society, Agent, Competition, Cooperation, JudgePicks
s = Society("multi-agent")
a = Agent("a", role="developer", model="claude-sonnet")
b = Agent("b", role="developer", model="claude-sonnet")
c = Agent("c", role="developer", model="claude-sonnet")
judge = Agent("judge", role="evaluator", model="claude-sonnet")
# 3-way competition
s.compete([a, b, c], Competition(resolve=JudgePicks(judge=judge)))
# 3-way cooperation
s.cooperate([a, b, c], Cooperation(shared=["design-doc"]))
Attempting to use a binary-only type with a group edge will raise a ValueError:
# This will raise ValueError at construction time
from claw.edge import GroupEdge
GroupEdge(members=[a, b, c], type=Delegation()) # ValueError!
Edge Configuration (Shared Fields)¶
All edge types inherit from EdgeType and share these configuration fields:
| Field | Type | Default | Description |
|---|---|---|---|
artifacts |
list[Artifact] |
[] |
Artifacts that flow along this edge |
events |
list[str] |
[] |
Allowed event types on this edge (extensible strings) |
max_rounds |
int \| None |
None |
Maximum interaction rounds before termination |
timeout |
timedelta \| None |
None |
Wall-clock timeout per round |
on_timeout |
TimeoutPolicy |
ESCALATE |
Policy when a round times out |
Timeout policies¶
The on_timeout field accepts a TimeoutPolicy enum with three options:
| Policy | Behavior |
|---|---|
TimeoutPolicy.ESCALATE |
Route the timeout to an upstream agent for resolution (default) |
TimeoutPolicy.RETRY_ONCE |
Retry the timed-out operation exactly once |
TimeoutPolicy.TERMINATE |
Stop execution on the affected edge immediately |
from datetime import timedelta
from claw import Oversight, TimeoutPolicy
s.connect(coder, reviewer, Oversight(
max_rounds=3,
timeout=timedelta(minutes=5),
on_timeout=TimeoutPolicy.TERMINATE,
))
Attaching artifacts to edges¶
Artifacts can be attached to edges so they flow along the relationship. This is how agents share work products.
from claw import Cooperation, StringArtifact
spec = StringArtifact(name="api-spec", max_tokens=8000)
s.connect(frontend, backend, Cooperation(
shared=["api-contract"],
artifacts=[spec],
))
When to Use Each Type¶
Use this decision matrix to pick the right edge type for your scenario:
| Scenario | Edge Type | Why |
|---|---|---|
| Manager assigns work to developer | Delegation | One-way task flow with accept/reject |
| Code review | Oversight | Asymmetric visibility -- reviewer sees all, author sees feedback |
| Pair programming | Cooperation | Full mutual visibility, shared output |
| Competitive coding challenge | Competition | Isolated work, judged result |
| API negotiation between teams | Coopetition | Cooperate on interface, compete on implementation |
| Editorial review of a document | Oversight | Editor adjudicates quality |
| Brainstorming with equal peers | Cooperation | No hierarchy, full sharing |
| Red team vs. blue team | Competition | Adversarial isolation is the point |
| Standards committee | Coopetition | Shared goals with competing proposals |
Rules of thumb:
- If one agent defines the task and another executes it, use Delegation.
- If one agent evaluates another's work, use Oversight.
- If agents work together as equals, use Cooperation.
- If agents should not see each other's work, use Competition.
- If agents share some context but compete on specific outputs, use Coopetition.
Resolution Strategies¶
Competition and Coopetition edges require a resolution strategy -- a mechanism for selecting among competing outputs. Claw provides three built-in strategies.
JudgePicks¶
A designated judge agent evaluates all submissions and picks a winner.
from claw import Agent, Competition, JudgePicks
judge = Agent("judge", role="evaluator", model="claude-sonnet")
Competition(
resolve=JudgePicks(
judge=judge,
criteria=["correctness", "readability", "performance"],
on_neither="escalate",
),
)
| Field | Type | Default | Description |
|---|---|---|---|
judge |
Agent |
(required) | The agent that evaluates submissions |
criteria |
list[str] |
[] |
Evaluation criteria (e.g., ["correctness", "performance"]) |
output_schema |
JsonSchema |
{"winner": str, "rationale": str} |
JSON Schema for the judge's structured output |
on_neither |
str |
"escalate" |
Policy when no submission meets criteria ("escalate", "retry", "best_effort") |
MajorityVote¶
Multiple voter agents each cast a vote. The submission with the most votes wins.
from claw import Agent, Competition, MajorityVote
voter1 = Agent("voter1", role="reviewer", model="claude-sonnet")
voter2 = Agent("voter2", role="reviewer", model="claude-sonnet")
voter3 = Agent("voter3", role="reviewer", model="claude-sonnet")
Competition(
resolve=MajorityVote(voters=[voter1, voter2, voter3]),
)
| Field | Type | Default | Description |
|---|---|---|---|
voters |
list[Agent] |
[] |
Agents that participate in voting |
Escalate¶
Escalate to a designated agent for resolution. Typically used as a fallback when automated resolution fails (deadlock, all submissions rejected, etc.).
from claw import Oversight
from claw.resolve import Escalate
s.connect(coder, reviewer, Oversight(
max_rounds=3,
on_deadlock=Escalate(to="tech-lead", summary=True),
))
| Field | Type | Default | Description |
|---|---|---|---|
to |
str |
(required) | Name of the agent to escalate to |
summary |
bool |
True |
Whether to include a summary of the situation |
Custom strategies¶
Any object that satisfies the ResolveStrategy protocol can be used as a resolution strategy. The protocol is defined as a runtime-checkable Protocol class, so you can implement your own strategies by conforming to the interface.
Querying Edges¶
Once you have built a society, you can inspect its edges:
# All binary edges
s.edges
# All group edges
s.group_edges
# All edges (binary + group)
s.all_edges
# Edges involving a specific agent
s.edges_of(coder)
# Find a binary edge between two agents
s.edge_between(coder, reviewer)
Complete Example¶
Here is a full example that uses multiple edge types in a single society:
from claw import (
Agent,
Competition,
Cooperation,
Delegation,
JudgePicks,
Oversight,
Society,
)
# Create the society
s = Society("software-team", description="A complete software development team")
# Define agents
pm = Agent("pm", role="project-manager", model="claude-sonnet")
arch = Agent("architect", role="system-architect", model="claude-opus")
dev1 = Agent("dev1", role="developer", model="claude-sonnet")
dev2 = Agent("dev2", role="developer", model="claude-sonnet")
reviewer = Agent("reviewer", role="code-reviewer", model="claude-sonnet")
# PM delegates work to the architect
s.connect(pm, arch, Delegation())
# Architect and PM cooperate on system design
s.connect(arch, pm, Cooperation(shared=["architecture-doc"]))
# Two developers compete on implementation
s.compete(
[dev1, dev2],
Competition(
resolve=JudgePicks(
judge=reviewer,
criteria=["correctness", "test-coverage", "readability"],
),
),
)
# Reviewer oversees the winning implementation
s.connect(dev1, reviewer, Oversight(max_rounds=3))
s.connect(dev2, reviewer, Oversight(max_rounds=3))
print(f"Society '{s.name}' has {len(s.agents)} agents and {len(s.all_edges)} edges")