ADR-0015: Split into a two-package workspace (strands-teams + code-context-agent)¶
Date: 2026-07-16
Status: accepted
Context¶
Through v3, code-context-agent was a single distribution that mixed two concerns that change for different reasons:
- A domain-agnostic agent-teams framework — coordinator construction, team dispatch, findings/artifact persistence, narrative scoring, the hook stack, the Rich/JSON display, layout, and settings.
- A codebase-analysis use case — the discovery/git/BM25/shell tool roster, the GitNexus and context7 MCP providers, the deterministic indexer, the
AnalysisResultoutput model, and the coordinator prompt templates.
Because both lived in one importable package, the framework could not be reused for any other domain without dragging in code-context specifics, and the tool surface had accreted features that no longer earned their keep. The single package also carried subsystems that had drifted out of the core value proposition: a deterministic verdict engine, temporal risk-trend computation, a GitHub issues provider, a ci-init workflow generator, and a FastMCP server plus a multi-repo registry exposed through a serve command. Each added dependencies, test surface, CLI commands, and documentation that the primary analyze/index flow did not need.
A separate line of drift was the multi-agent execution model. The pipeline had moved from a hand-rolled Swarm orchestration (ADR-0012, already superseded by ADR-0013's coordinator dispatch) toward strands-agents' native team/Swarm primitives. Standing on the framework's own dispatch instead of bespoke glue was only practical once the framework code was cleanly separated from the use case.
Forces at play:
- Reuse: the teams framework should be installable and testable on its own, with a stable
UseCasecontract that any domain can implement. - Focus: the CLI should present only the surviving, load-bearing commands.
- Dependency hygiene: framework-only dependencies should not leak into the use case, and use-case-only dependencies (GitNexus/context7 providers, the indexer's scanners) should not burden the framework.
- Release discipline: the split is a breaking change to the import surface and the CLI, so it must land as a major version bump.
Decision¶
Restructure the repository as a uv workspace with two members under packages/:
strands-teams(import packagestrands_teams) — the domain-agnostic framework. Public surface:UseCase(+validate_use_case),run_teams/run_teams_sync,create_coordinator,TeamsLayout,PhaseSpec,TeamsSettings, the team tools (dispatch_team,read_team_findings,write_artifact,score_narrative,enrich_artifact), the narrative rubric, the hook stack, and the Rich/JSON display. Depends only onstrands-agents>=1.47, pydantic, jinja2, loguru, and rich.code-context-agent(import packagecode_context_agent) — the codebase-analysis use case. ShipsCodebaseAnalysisUseCase(implementing thestrands_teams.UseCasecontract), theanalyze/index/checkCLI, the deterministic indexer, the discovery/git/BM25/shell tools, the GitNexus and context7 MCP providers, and theAnalysisResultoutput model. Depends onstrands-teams(via[tool.uv.sources] workspace = true) plus cyclopts and rank-bm25.
The root pyproject.toml is a virtual workspace project (no [project] table). It declares [tool.uv.workspace] members = ["packages/*"], hosts the repo-wide dev/docs/security dependency groups, and holds the shared tool configuration (ruff, ty, coverage over both code_context_agent and strands_teams, pytest with --import-mode=importlib, bandit, pip-licenses). Commitizen lives in the code-context-agent member and its version_files points at packages/code-context-agent/src/code_context_agent/__init__.py.
Alongside the split, the following subsystems are dropped:
- verdict engine and its CLI command,
- temporal risk-trend module,
- GitHub issues provider,
- ci-init workflow generator,
- FastMCP server and the multi-repo registry, and the
servecommand.
The surviving CLI surface is analyze, index, and check. Execution uses strands-agents' native team/Swarm dispatch through the framework's run_teams runner rather than bespoke orchestration. The strands_tools graph tool is also dropped from the analysis roster.
Because this changes both the import surface and the CLI, it lands as a breaking change (major version bump, feat!).
Consequences¶
Positive:
- The teams framework is independently reusable and independently testable; a new domain implements
UseCasewithout importing any code-context specifics. - The CLI and dependency graph are smaller and match the actual value path.
- Framework and use-case dependencies are cleanly separated; each package's
pyproject.tomldeclares only what it needs. - Standing on native strands Swarm dispatch removes hand-rolled orchestration glue and keeps the framework aligned with the SDK.
- Coverage, lint, type-check, and the docs reference now span both packages via workspace-aware configuration.
Negative:
- Breaking change: importers of the old
code_context_agent.*framework paths and users ofserve/verdict/ci-initmust migrate. This supersedes the FastMCP server (ADR-0004) and the multi-repo registry (ADR-0010). - Two packages mean two
pyproject.tomlfiles and a lockfile that must resolve both members; contributors must understand the workspace layout. - Test collection requires
--import-mode=importlibbecause both packages ship a top-leveltestspackage.
Neutral:
strands-agentsis pinned to>=1.47in both packages for the native team APIs; the nightly dependency-update job can still bump it within that range.- This continues the trajectory of ADR-0012 → ADR-0013: the coordinator-dispatch model is retained, now expressed through the extracted framework.