@dataclass(frozen=True)
class SubagentDef:
name: str
description: str = ''
system_prompt: str = ''
model: Optional[str] = None
permission_mode: Optional[PermissionMode] = None
max_iterations: int = 5
max_tool_calls: int = 8
tool_whitelist: Optional[frozenset[str]] = None
disallowed_tools: Optional[frozenset[str]] = None
max_depth: int = 1
isolation: str = 'shared'
background: bool = False
effort: Optional[str] = NoneImmutable definition loaded from .teaagent/subagents/. tool_whitelist restricts which parent tools are inherited. max_depth controls how many delegation levels deep this agent can be started.
@dataclass(frozen=True)
class SubagentLineage:
parent_run_id: str
def_name: str
depth: int
isolation: str = 'shared'
batch_index: Optional[int] = None
worktree_path: Optional[str] = None
container_path: Optional[str] = None
def to_dict(self) -> dict[str, str | int]: ...Tracks the parent→child relationship. container_path is a legacy field name for directory-snapshot (kept for backward compatibility).
@dataclass(frozen=True)
class SubagentSession:
session_id: str
def_name: str
parent_run_id: str
status: str
started_at: str # ISO-8601
depth: int = 0
batch_index: Optional[int] = None
isolation: str = 'shared'
worktree_path: Optional[str] = None
container_path: Optional[str] = None
completed_at: Optional[str] = None
iterations: int = 0
tool_calls: int = 0
cost_cents: float = 0.0
final_answer: str = ''
review: Optional[dict[str, Any]] = None
@property
def lineage(self) -> SubagentLineage: ...@dataclass(frozen=True)
class IsolationContext:
parent_root: Path
child_root: Path
isolation: str
worktree_path: Optional[Path] = None
container_path: Optional[Path] = None
container_id: Optional[str] = None
cpu_quota: Optional[float] = None
memory_limit: Optional[str] = None
def cleanup(self) -> None: ...cleanup() removes worktrees, snapshot directories, or Docker containers depending on isolation. Always safe to call multiple times (uses check=False/ignore_errors=True).
@dataclass
class SubagentApprovalRequest:
request_id: str
subagent_id: str
parent_run_id: str
subagent_name: str
tool_name: str
tool_arguments: dict[str, Any]
permission_mode: str
isolation: str
batch_index: Optional[int] = None
worktree_path: Optional[str] = None
created_at: str = ... # ISO-8601 UTC
status: ApprovalRequestStatus = PENDING
approved_at: Optional[str] = None
denied_at: Optional[str] = None
denial_reason: Optional[str] = None
timeout_seconds: int = 180
def to_dict(self) -> dict[str, Any]: ...class ApprovalRequestStatus(Enum):
PENDING = 'pending'
APPROVED = 'approved'
DENIED = 'denied'
TIMEOUT = 'timeout'
CANCELLED = 'cancelled'File: _loader.py:16
Pre-conditions: root is a Path. .teaagent/subagents/ need not exist.
Post-conditions: Returns {} if the directory is absent. Otherwise, returns a dict keyed by SubagentDef.name for each parseable file with a valid name field. Files with unsupported suffixes or missing/empty name are silently skipped.
Supported formats: .yaml, .yml (PyYAML or fallback parser), .json, .md (YAML frontmatter + body as system_prompt).
File: _isolation.py:77
Normalizes isolation mode string. Returns DEFAULT_SUBAGENT_ISOLATION for None/empty. Returns None for unrecognized values. Maps deprecated alias 'container' → 'directory-snapshot' silently.
prepare_subagent_isolation(parent_root, *, isolation, session_key, cpu_quota, memory_limit) -> tuple[IsolationContext | None, str]
File: _isolation.py:112
Pre-conditions: isolation is one of SUPPORTED_SUBAGENT_ISOLATIONS. session_key must be unique for the current parent run.
Post-conditions:
- Returns
(IsolationContext, '')on success. - Returns
(None, error_message)on failure. - Deprecated aliases emit a
DeprecationWarningbefore normalizing. - Worktree isolation requires
.gitto exist inparent_root. - Docker isolation requires
docker --versionto succeed.
Exceptions: OSError from snapshot copy is caught and returned as (None, message).
File: _isolation.py:280
Produces a filesystem-safe, collision-resistant key: {safe_parent[:12]}-{safe_def_name}-{uuid4().hex[:8]}.
File: _manager.py:48
Loads subagent defs from disk. Does not register tools.
Called by register_subagent_tools to store the parent ToolRegistry reference.
Returns all loaded defs sorted by name.
Case-insensitive, dash/underscore-normalized lookup.
run_subagent(*, task, parent_run_id, depth, def_name=None, max_iterations=None, max_tool_calls=None, batch_index=None, isolation='shared', skill_path=None, skill_risk_level=None) -> dict[str, Any]
Pre-conditions:
taskis a non-empty string.depthis the parent's current depth; the child will run atdepth + 1.isolationis one of the supported isolation modes.
Post-conditions:
- Returns a result dict with
statuskey. - On success:
{'run_id', 'status', 'iterations', 'tool_calls', 'cost_cents', 'final_answer', 'lineage', ['review'], 'message'}. - On error:
{'run_id': '', 'status': 'error', 'iterations': 0, 'tool_calls': 0, 'final_answer': '', 'message': '<reason>', ['lineage']}. - IsolationContext is always cleaned up via
finally. - Session is stored in
self._sessions[run_id]on success.
Exceptions: Exceptions from run_chat_agent propagate after cleanup.
File: _approval_queue.py:122
Creates in-memory queue. If workspace_root is given, creates/loads ApprovalQueueStore and calls reload_from_store().
Blocking sync method. Submits request, writes to disk, polls with 0.25s sleep until approved/denied/timeout. Returns True if approved, False otherwise.
Async version. Uses asyncio.Future and asyncio.wait_for(future, timeout=180).
Marks PENDING→APPROVED, sets threading.Event, persists to disk. Returns False if request not found or not PENDING.
Same as approve, but PENDING→DENIED.
Convenience: approves all PENDING requests. Returns count.
Convenience: denies all PENDING requests. Returns count.
Thread-safe snapshot of all PENDING requests.
Thread-safe lookup by ID.
Merges disk state into memory. Resolves waiting futures/events for requests that have changed status externally.
Removes terminal (non-PENDING) requests without associated futures.
File: _approval_queue_store.py:40
Queue files stored at workspace_root/.teaagent/approval_queues/<parent_run_id>.json.
Atomic write via temp-file + os.replace. Optionally signs payload with HMAC-SHA256.
Reads and verifies queue file. Returns empty snapshot on missing file or HMAC failure.
update_request_status(parent_run_id, request_id, status, *, reason=None, approved_by='human') -> bool
Cross-process approve/deny. Acquires exclusive lock, reads, modifies, writes atomically. Returns False if request not found or not PENDING.
Removes queue files older than max_age_seconds with no pending requests.
| Function | Signature | Description |
|---|---|---|
get_approval_queue |
(parent_run_id, *, workspace_root) -> CentralizedApprovalQueue |
Get-or-create from global registry |
try_get_approval_queue |
(parent_run_id, *, workspace_root) -> Optional[...] |
Get only if exists (no side-effects) |
snapshot_pending_subagent_requests |
(parent_run_id=None, *, workspace_root) -> list[dict] |
Serialized pending requests for UI |
approve_request_cross_process |
(workspace_root, parent_run_id, request_id, *, approved_by) -> bool |
Disk-level approve for out-of-process callers |
deny_request_cross_process |
(workspace_root, parent_run_id, request_id, *, reason) -> bool |
Disk-level deny |
make_centralized_subagent_approval_handler |
(*, parent_run_id, subagent_id, ...) -> ApprovalHandler |
Factory for subagent-scoped sync handler |
should_use_centralized_approval |
(*, parent_run_id, batch_index, parallel_mode) -> bool |
Decision predicate |
cleanup_queue |
(parent_run_id, *, workspace_root) -> None (async) |
Remove queue from global registry + cleanup |
Registered tools (with their schemas):
| Tool name | Input required | Description |
|---|---|---|
subagent |
task (str) |
Generic single-subagent delegation |
subagent_<name> |
task (str) |
Named def-specific delegation |
subagent_batch |
tasks (list) |
Parallel batch; each item has task, optional def_name, max_iterations, max_tool_calls, isolation |
team |
task, team_name |
Multi-specialist team run |
All subagent tools share optional inputs: max_iterations, max_tool_calls, isolation.