Implement ContainerToolExecutor for delegating tool invocations to
devcontainer environments with full I/O forwarding. Add PathMapper for
bidirectional host/container path translation. Wire container routing
into ToolRunner with graceful fallback when no executor is configured.
Add container_metadata field to ToolInvocation for tracking execution
context.
New modules:
- tool/container_executor.py: ContainerToolExecutor, ContainerConfig,
ContainerMetadata, ContainerExecutionError, ContainerTimeoutError
- tool/path_mapper.py: PathMapper with host_to_container/container_to_host
Modified:
- tool/runner.py: container execution routing via ExecutionEnvironment
- domain/models/core/change.py: container_metadata on ToolInvocation
- tool/__init__.py: new public exports
Review fixes applied:
- Add Alembic migration m6_004 for container_metadata_json column
- Enforce _MAX_OUTPUT_BYTES (50 MiB) truncation in _run_command()
- Fix path traversal in sync_results_to_host (Path.is_relative_to)
- Allow spaces in _looks_like_path() for valid filesystem paths
- Preserve negative exit codes from signal kills in metadata
- Add default=str to json.dumps(invocation.arguments) safety net
- Log warnings when path mapping recursion depth exceeded
- Warn when devcontainer binary not found on PATH
- Use default allow_nan for host-path JSON validation in runner.py
(only container path requires RFC 7159 strict mode)
- Reject URL-like patterns in _looks_like_path() to avoid false
positives on API routes, protocol-relative URIs, and query strings
- Add extract_container_metadata() static helper on
ContainerToolExecutor as bridge for ToolInvocation wiring
- Use raw_stdout bytes in sync_results_to_host to prevent
binary file corruption from text-mode decode/re-encode
- Apply posixpath.normpath() in workspace_folder validator and
reject path components containing '..'
- Check result.timed_out in sync_results_to_host and raise
ContainerTimeoutError instead of always raising ContainerExecutionError
- Detect overlapping host_root/container_root in PathMapper and
raise ValueError to prevent corrupt bidirectional mappings
- Wrap host-side I/O in sync_results_to_host with try/except
OSError to produce ContainerExecutionError on write failure
- Enforce int(timeout) in _build_exec_command to prevent shell
injection via malicious objects with __str__ methods
- Change ToolResult validator from 'not self.error' to
'self.error is None' so empty-string errors are accepted
- Iterate required list directly in ToolRunner schema validation
to detect fields listed in required but absent from properties
Closes#515
Wire per-service retry policies and circuit breakers into the service
layer via ServiceRetryWiring, backed by ServiceRetryPolicyRegistry and
configurable through Settings environment variables.
Production hardening from code review:
- Fix TOCTOU race in CircuitBreaker._on_success (half-open state)
- Add half-open probe limit to prevent unbounded concurrent requests
- Track all exception types for circuit breaker failure counting
- Detect async callables wrapped in functools.partial and callable objects
- Enforce spec-compliant 2s minimum for linear backoff strategy
- Enforce 0.1s floor for fixed backoff strategy
- Add retry amplification guard via contextvars nesting depth tracking
- Cap total retry wall-clock time at 300s (MAX_RETRY_TOTAL_TIMEOUT)
- Sanitize exception messages in retry logs to prevent secret leakage
- Fix wrap_service_method TOCTOU by holding cache lock for full operation
- Deep-copy default policies to prevent cross-policy mutation
- Warn on unknown override keys in apply_overrides
- Guard apply_overrides against non-dict and deeply nested JSON values
- Read circuit breaker state under lock in is_circuit_open
- Catch RecursionError in JSON config parsing
- Add total_timeout + nesting guard to retry_service_operation decorator
- Extend secret sanitization to Authorization headers, private_key,
connection_string, and access_key patterns
- Enforce 0.1s floor on jitter backoff strategy
- Cache wait strategies per service in ServiceRetryWiring (M3)
- Reset failure_count to 0 when entering half-open from open (M6)
- Use cached _get_wait_strategy() in execute()/async_execute()
- Move circuit-open logging out of _on_failure lock scope to prevent
holding the lock during potentially slow I/O (F1)
- Pass total_timeout=MAX_RETRY_TOTAL_TIMEOUT to wrap_service_method
retry_service_operation call for consistency with execute() (F4)
- Capture failure_count into local variable inside lock scope before
logging outside the lock, preventing stale reads from concurrent
threads in CircuitBreaker.call() and async_call() (F1)
- Deep-copy module-level DEFAULT_DATABASE_RETRY and DEFAULT_CIRCUIT_BREAKER
in ServiceRetryPolicyRegistry.get() for auto-generated unknown service
policies, preventing shared mutable state corruption (F1)
- Unify CircuitBreaker to a single threading.Lock for sync and async (P1-1)
- Restore BaseException permit in half-open path to prevent permit leak (P1-6)
- Prevent CircuitBreakerOpen cascading into failure_count (S2)
- Protect all logger calls with contextlib.suppress (S3, S4)
- Replace time.time() with time.monotonic() for monotonic timing (S5)
- Add distinct log events for half-open and closed transitions (S11, S12)
- Track pre-existing services so second apply_settings_defaults only
targets newly registered services (P1-2)
- Lazy circuit breaker creation via _get_or_create_cb() (P1-3)
- Reject async callables in sync execute() with TypeError (P1-5)
- Strengthen retry predicate to retry_if_exception_type(Exception) &
retry_if_not_exception_type(CircuitBreakerOpen) (S1)
- Add lock on _get_wait_strategy cache access (P2-16)
- Truncate raw JSON to 80 chars in override warning (P2-17)
- Warn on non-dict JSON overrides (P2-29)
- Debug log for nesting guard bypass (S13)
- Deep-copy from get() and all_policies() in registry (P1-4)
- Thread-safe registry with threading.Lock (P2-15)
- Robust exception handling in apply_overrides get() (P2-18)
- Log ValidationError details on override failure (P2-19)
- Sanitize service_name via _safe_service_name() (P2-28)
- Warn on non-dict sub-key values in overrides (P2-30)
- Allowlist for is_read_only_plan_operation phases (P2-10)
- Cap retry_auto_debug sleep at 60s (P2-11)
- Use is-not-None instead of falsy checks for error values (P2-12)
- Extend secret regex with bearer, session_id, auth_token,
refresh_token, client_secret patterns (P2-25)
- Pre-truncate error messages to 2000 chars before regex (P2-26)
- Add upper bounds on retry Settings fields (P2-7)
- Add cross-field validator max_delay >= base_delay (P2-8)
- Case-insensitive backoff strategy validation (P2-21)
- Add half_open_max_successes setting (S10)
- Remove phantom ContextFragment from services __all__ (ImportError fix)
- Export ServiceRetryWiring from application.services package
- Include sanitised error context in TypeError logging fallback
- Initialise RetryContext.attempt_count to 1 for bare context-manager usage
- Introduce CircuitBreakerState StrEnum replacing raw string literals
- Fix vacuous CircuitBreakerOpen propagation assertions in BDD steps
- Replace tautological logging test with structlog capture verification
- Assert circuit breaker existence instead of silently skipping on None
- Add Unicode control-char rejection validator to ServiceRetryPolicy.service_name
- Add name parameter with service= in all log calls
- Add extra="forbid" to all 3 Pydantic models
- Deep-copy _SERVICE_DEFAULTS construction
- Key normalisation (.strip()) in get() and apply_overrides()
- Add cooldown <= recovery_timeout validator
- Async guard on RetryContext.execute()
- Nesting guard on RetryContext.execute()/async_execute()
- stop_after_delay(300.0) on RetryContext
- retry_auto_debug async-only guard, dict result fix, sleep guard
- Retry-attempt logging in RetryContext
- Module-level docs for contextlib.suppress(TypeError) rationale
- Exhaustion log on retry failure
- Startup log in __init__; name=service_name to CircuitBreaker
- log_after_retry guarded to not fire on first-attempt success
- get_retry_decorator now includes logging callbacks
- Changed retry_backoff_strategy from str to RetryStrategy StrEnum
Closes#313
Temporal metadata fields (validFrom, validUntil, isCurrent, isRevisionOf)
on UKO InformationUnit nodes enable revision chain tracking: when code
changes, old nodes are marked historical and new revision nodes are
created with back-links. Three storage tiers (hot/warm/cold) filter
nodes by temporal scope (current/recent/all) with configurable retention
(warm_retention_hours default 24h, cold_retention_days default 90d).
Includes TemporalMetadata, TemporalNode, RevisionChain, TierQueryResult,
TierRetentionConfig frozen domain models, TemporalBackend protocol,
InMemoryTemporalBackend stub, TemporalService with structlog and DI,
BackendSet.temporal typing upgrade from object|None to TemporalBackend|None.
67 Behave scenarios, 8 Robot Framework tests, ASV benchmarks, and
reference documentation.
ISSUES CLOSED: #577
Implement the UKOIndexer service that produces UKO triples from resources
using pluggable domain-specific analyzers, wraps each triple with provenance
metadata, and simultaneously indexes into text, vector, and graph backends.
Key design decisions and components:
- UKOIndexer orchestrates the full index lifecycle: add_resource,
update_resource (remove-then-add), remove_resource, and maintenance
triggers. Each operation fires lifecycle hooks (on_indexed, on_removed,
on_error) so callers can observe progress.
- Analyzer selection is pluggable via ContentAnalyzer protocol. The indexer
accepts a registry mapping resource types to analyzers. PythonAnalyzer
and MarkdownAnalyzer are provided as built-in implementations.
- LocationContentReader protocol abstracts file I/O with a base_dir
parameter for path-traversal prevention (post-resolve validation rejects
paths escaping the base directory and non-regular files).
- UKOTriple model includes a @model_validator ensuring at least one of
object_uri or object_value is populated, preventing empty triples at
construction time.
- Triple removal uses scoped deletion via uko:sourceResource predicate to
avoid shared-subject collision — only triples originating from the
specific resource are removed, not all triples for a shared subject.
- _resource_subjects.pop is deferred until after all backend removal
operations succeed, preventing inconsistent state on partial failure.
- analyzer.analyze() is wrapped in try/except so that analyzer errors
produce an IndexResult with error details rather than propagating
exceptions to callers.
- All lifecycle hook calls are guarded via _fire_on_indexed,
_fire_on_removed, and _fire_on_error helpers that catch and log hook
exceptions without disrupting the indexing pipeline.
- max_triples parameter (default 50,000) bounds analyzer output size to
prevent runaway resource consumption.
- ResourceFileWatcher monitors filesystem paths via watchdog and triggers
re-indexing callbacks on file changes with configurable debouncing.
Emits RESOURCE_MODIFIED domain events via EventBus when file changes
are detected. Debounce timers coalesce rapid edits into a single
callback invocation. Thread-safe design with daemon threads for clean
shutdown.
- SearchResult.__post_init__ validates score is in [0.0, 1.0], correctly
rejecting NaN values.
- Placeholder embedding uses [1.0] instead of [float(len(content))] to
avoid leaking content size information.
- isinstance check on graph_backend ensures GraphIndexBackend protocol
compliance at runtime.
- Test doubles extracted to features/mocks/uko_indexer_mocks.py for reuse
across BDD steps and Robot helpers.
Spec reference: Architecture > ACMS > Real-time Index Synchronization
(specification.md lines ~43205-43300).
ISSUES CLOSED: #578
Implement StrategyCoordinator and FusionEngine as named facades over
the existing ACMS pipeline components, providing clean public APIs
for parallel strategy execution with proportional budget allocation
and fragment fusion with dedup/conflict resolution/knapsack packing.
Key changes:
- Add StrategyCoordinator with parallel execution and confidence-based budget allocation
- Add FusionEngine with URI+hash dedup, max-depth conflict resolution, greedy knapsack packing
- Add budget overage guard with lowest-relevance fragment dropping
- Add per-strategy max caps enforcement
- Wire into existing ContextAssemblyPipeline
- Add Behave BDD tests, Robot integration tests, ASV benchmarks
- Add docs/reference/acms_fusion.md
ISSUES CLOSED: #192
Implemented lazy container activation for devcontainer-instance resources
with ContainerLifecycleState enum tracking six states (inactive, starting,
active, stopping, stopped, error) with validated transitions. Extended
DevcontainerHandler with devcontainer up CLI integration and JSON output
parsing for container start. Added periodic health checking via
devcontainer exec ping with configurable interval. Added agents resource
stop and agents resource rebuild CLI commands for manual lifecycle
control. Wired session close and plan completion hooks to automatic
container cleanup. Includes lifecycle state persistence in resource
registry with timestamped transitions. Added Behave BDD tests, Robot
integration tests, and ASV activation latency benchmarks.
- Added remoteWorkspaceFolder absolute-path validation
- Aligned spec: handler name, rebuild types, --yes flag on stop/rebuild
- Added registry re-read in stop_container success path for consistency
- Added session_id field to ContainerLifecycleTracker for scoped cleanup
- Scoped stop_all_active_containers to session_id when provided
- Wired _cleanup_devcontainers into fail_apply and fail_execute
- Wired start_health_check into activate_container success path
- Restructured facade session close to always run container cleanup
even without session service (F4)
- Re-read tracker from registry in activate_container success path
- Added evict_terminal_trackers to cap registry growth
- Updated devcontainer_resources.md: health check auto-start, scoped
cleanup hooks, known limitations for eviction and sandbox_strategy
- Wired evict_terminal_trackers into stop_all_active_containers so
terminal-state trackers are actually evicted in production
- Made stop_container idempotent: returns early when container is
already in a terminal state instead of raising ValueError
- Fixed benchmark health check thread leak in TimeActivationLatency
by clearing registry after each timing loop
- Added rebuild pass-through (--reset-container flag to devcontainer up)
- Added host_workspace_path field on ContainerLifecycleTracker so
health probes use the host-side path for devcontainer exec
- Wired lazy activation into DevcontainerHandler.resolve() for
devcontainer-instance resources in non-running states
- Changed _default_strategy from SNAPSHOT to NONE (container
itself provides isolation; SandboxFactory raises NotImplementedError
for snapshot)
- Restricted _STOPPABLE_TYPES to devcontainer-instance only
(container-instance is not directly stoppable via CLI)
ISSUES CLOSED: #514
Add RepoIndexingService with incremental refresh, language detection,
SHA-256 hashing, and policy enforcement. Includes domain models,
DB persistence, DI wiring, Behave/Robot/ASV tests, and reference docs.
ISSUES CLOSED: #195
Added minimal LSP server entrypoint supporting initialize/shutdown/exit
handshake over JSON-RPC stdin/stdout transport with Content-Length
framing. Unsupported methods return MethodNotFound error with descriptive
message. Wired LSP requests through ACP facade in local mode. Added
agents lsp serve CLI command with --log-level flag, PID output, and
startup banner. Created reference documentation for the stub server.
Includes Behave BDD tests for protocol handshake, Robot smoke test, and
ASV startup latency benchmark.
ISSUES CLOSED: #203
Core domain types (FragmentProvenance, ContextFragment, ContextBudget,
ContextPayload) now extend their CRP counterparts via Pydantic v2
inheritance, ensuring isinstance compatibility across the model
hierarchy.
Key changes:
- CRP base types made frozen=True (no consumer mutates them)
- CRP AssembledContext fields changed from list to tuple (frozen consistency)
- Core types extend CRP bases: FragmentProvenance(CRPFragmentProvenance),
ContextFragment(CRPContextFragment), ContextBudget(CRPContextBudget),
ContextPayload(CRPAssembledContext)
- Removed duplicate ContextFragment dataclass from skeleton_compressor
- Updated project_context.py to pass tuples to frozen AssembledContext
- Added Behave tests (10 scenarios), Robot integration tests (3 cases),
and ASV benchmarks for the unified hierarchy
- Updated Known Limitations table in docs/reference/acms.md
ISSUES CLOSED: #569
- Add AsyncJob domain model with status state machine and Pydantic validation
- Add AsyncWorker service with configurable concurrency and job store
- Add CancellationToken, WorkerHealthReport, InMemoryJobStore
- Add AsyncJobModel SQLAlchemy model and Alembic migration (m6_003)
- Add 5 async config keys to Settings (worker_id, concurrency, poll_interval, max_retries, timeout)
- Add _check_async_worker_health diagnostic check in system.py
- Add comprehensive Behave BDD tests (~60 scenarios) with full step definitions
- Add Robot Framework integration tests (6 smoke tests)
- Add ASV benchmark suite for async execution
- Add architecture documentation
- Update vulture_whitelist with new public API symbols
- All quality gates pass: lint, typecheck, unit_tests, integration_tests, coverage_report (97%)
1. Wire async job creation into PlanLifecycleService:
- Add optional job_store parameter to __init__
- Add _maybe_enqueue_async_job() helper that checks settings.async_enabled
and job store presence before creating and enqueuing an AsyncJob
- Call helper from execute_plan() (phase="execute") and apply_plan()
(phase="apply") after phase transitions
- When async is disabled or no job store is configured, behaviour is
unchanged (silent no-op)
2. Redact secrets in failed job error messages:
- Apply shared.redaction.redact_value() to the error string before
persisting to AsyncJob.error_message, preventing accidental secret
leakage (e.g. API keys in exception text) into the audit trail
Documentation:
- S1: Added specification reconciliation note (ADR-style) to
async_architecture.md addressing tension between "No Plan Queuing"
clause and the async subsystem authorised by issue #312
ISSUES CLOSED: #312
Wire all four project context CLI commands (inspect, simulate, set, show)
to live ACMS pipeline services via ContextTierService and CRP models.
- context inspect: queries ContextTierService for tier metrics and
per-project fragments with filtering by strategy/focus/breadth/depth
- context simulate: dry-run context assembly using CRP models with
configurable token budget and assembly strategies
- context set: 12 new ACMS pipeline options (hot_max_tokens,
warm_max_decisions, cold_max_decisions, summary_max_tokens,
temporal_scope, auto_refresh, focus_area, breadth, depth,
assembly_strategy, retrieval_strategy, summary_strategy)
- context show: displays ACMS pipeline configuration alongside policy
- `context inspect` displayed global tier fragment counts (hot/warm/cold)
across all projects instead of counts for the target project only.
Add `ContextTierService.get_scoped_metrics(project_names)` which uses
`ScopedBackendView` to filter fragment counts to the specified projects
while keeping hit/miss counters as global service-level cache metrics.
Update `context_inspect()` to call `get_scoped_metrics([project])`
instead of `get_metrics()`.
- `context simulate --focus` accepted focus URIs and passed them to the
`ContextRequest` model but never used them to filter the fragment list,
making the `--focus` flag a no-op.
Add focus URI filtering in `_simulate_context_assembly()` after
`get_scoped_view()` — filters `project_fragments` by matching each
fragment's `resource_id` against the supplied focus URIs.
Also fixes redaction false positives for hot_max_tokens and
summary_max_tokens keys, and Rich Console line-wrapping in test
output that caused JSON parse failures.
Includes 28 new Behave BDD scenarios for wiring coverage, updated
Robot Framework integration tests, and reference documentation.
ISSUES CLOSED: #499
Implement safety profile resolution and enforcement in the tool
execution pipeline, replacing the NotImplementedError stub with
working precedence logic and runtime safety checks.
Core changes:
- resolve_safety_profile() now resolves plan > action > project >
global precedence, returning the highest-priority non-None profile
(or DEFAULT_SAFETY_PROFILE with GLOBAL provenance when all None)
- ToolExecutionContext gains an optional safety_profile field
- ToolRuntime._enforce_capabilities() extended with three new checks:
* Unsafe tool gating: blocks tools with unsafe=True when profile
has allow_unsafe_tools=False (ToolSafetyViolationError)
* Skill category allow-list: blocks tools whose skill category
is not in allowed_skill_categories (ToolSafetyViolationError)
* Checkpoint requirement: OR-combines ctx.require_checkpoints
with safety_profile.require_checkpoints
- New ToolSafetyViolationError in tool error hierarchy
Test coverage:
- 30 updated BDD scenarios in safety_profile.feature (resolve
precedence replaces NotImplementedError stub test)
- 24 new BDD scenarios in safety_profile_enforcement.feature
- 9 Robot Framework integration smoke tests
- 4 ASV benchmark suites (construction, serialization, resolution,
provenance enum)
All nox sessions pass (typecheck 0 errors, unit_tests 7735 scenarios
0 failures, coverage 97%, integration_tests 9/9 passed, benchmarks
complete).
ISSUES CLOSED: #345
Add LLMTrace Pydantic v2 domain model with all required fields (trace_id,
plan_id, decision_id, actor, provider, model, prompt_tokens, completion_tokens,
cost_usd, latency_ms, tool_calls, context_hash, streaming, retry_count, error).
Define 14 OperationalMetricKey values (PLAN_DURATION_MS, PLAN_TOTAL_COST_USD,
PLAN_DECISION_COUNT, ACTOR_INVOCATION_COUNT, ACTOR_LATENCY_MS,
TOOL_INVOCATION_COUNT, TOOL_ERROR_RATE, CONTEXT_BUILD_TIME_MS,
CONTEXT_TOKEN_COUNT, LLM_CALL_COUNT, LLM_TOTAL_TOKENS, LLM_TOTAL_COST_USD,
LLM_AVG_LATENCY_MS, SUBPLAN_COUNT) with MetricEntry model and MetricCollector.
Add llm_traces database table (LLMTraceModel) with LLMTraceRepository for
persistence. TraceService provides recording, querying, metric computation,
plan lifecycle hooks, and optional LangSmith forwarding when
LANGCHAIN_TRACING_V2=true.
Wired into DI container as trace_service. Includes 28 Behave BDD scenarios,
6 Robot Framework smoke tests, 3 ASV benchmark suites, and reference
documentation.
Fix pre-existing cli_core server_mode test flake by mocking
resolve_server_mode in test steps to avoid stale config file interference.
Closes#500
Add hierarchical decomposition with 4+ levels and bounded context per
subplan. Implement decomposition heuristics (max_files_per_subplan,
max_tokens_per_subplan, language/dir clustering). Add dependency closure
computation for large graphs and DAG execution ordering. Add bounded
dependency closure with cutoff thresholds and memoization for 10K+
files. Record decomposition decisions in DecisionService
(strategy_choice + subplan_spawn entries).
New modules:
- decomposition_models.py: DecompositionConfig, DecompositionNode,
DecompositionResult, DependencyEdge, DependencyGraph
- decomposition_clustering.py: ClusteringStrategy with directory,
language, and size clustering plus deterministic sort
- decomposition_graph.py: DependencyClosureComputer with bounded
closure, topological sort, cycle detection, and memoization
- decomposition_service.py: DecompositionService orchestrating
hierarchy building and decision recording
Settings: planner_max_depth, planner_max_files_per_subplan,
planner_max_tokens_per_subplan, planner_min_files_per_subplan
Closes#205
Add domain models, application service, CLI integration, and full test
coverage for multi-project subplan orchestration.
New components:
- MultiProjectMetadata, ProjectScope, ProjectDependency domain models
- MultiProjectService for creating/managing multi-project plans
- CLI display of multi-project metadata in plan commands
- Behave BDD tests (20 scenarios), Robot Framework integration tests,
ASV benchmarks, and reference documentation
Also fixes pre-existing test flakiness in cli_core, core_cli_commands,
cli_plan_context_commands, and helper_server_stubs caused by environment
leakage and path-with-spaces issues.
ISSUES CLOSED: #199
Behave steps, benchmarks, vulture whitelist, and docs referenced
renamed methods (get_decisions_for_plan, get_decision_tree). Updated
to use the actual API names (list_decisions, get_tree) and the kwargs
record_decision signature.
ISSUES CLOSED: #172
- Remove global _PLAN_ID; generate per-step plan IDs on context (#8)
- Fix sham orphan test; build children_map from all decisions (#1)
- Delete dead constants; use _PATCH_RESUME_SVC_MOD in resume steps (#2)
- Remove dead _resolve_active_plan_id mock from _invoke_correct (#5)
- Make --mode/--guidance required Typer options (#3)
- Show alternatives by default; remove --show-alternatives flag (#4)
- Strengthen weak assertions on depth-limit and show-superseded (#6)
- Add negative assertions for error type conflation (#7)
ISSUES CLOSED: #174
Add `plan explain` and `plan tree` CLI commands that format decision
trees in json/yaml/table/rich formats. Flags control views for
superseded decisions, context snapshots, and reasoning details.
- plan explain <decision_id>: renders a single decision with optional
--show-context, --show-reasoning, --show-alternatives flags
- plan tree <plan_id>: renders full decision tree with optional
--show-superseded and --depth flags
- BFS tree building uses collections.deque (no list.pop(0))
- Behave BDD scenarios (14 scenarios, 54 steps)
- Robot Framework smoke tests with helper script
- ASV benchmarks for explain formatting and tree operations
- Updated docs/reference/plan_cli.md and CHANGELOG.md
ISSUES CLOSED: #174
Wire all AcpLocalFacade operation handlers to their corresponding
application services via constructor-injected service dependencies:
- session.create/close delegate to SessionService
- plan.create/execute/status/diff/apply delegate to PlanLifecycleService
- registry.list_tools delegates to ToolRegistry
- registry.list_resources delegates to ResourceRegistryService
- event.subscribe delegates to AcpEventQueue
- context.get returns stub pending ACMS ContextAssemblyPipeline
Add domain-to-ACP error code mapping via map_domain_error() translating
ResourceNotFoundError to NOT_FOUND, ValidationError to VALIDATION_ERROR,
PlanError to PLAN_ERROR, BusinessRuleViolation to INVALID_STATE, and
other domain exceptions to their corresponding ACP error codes.
Handlers gracefully fall back to stub responses when services are absent.
Includes 21 Behave scenarios (features/acp_facade_wiring.feature) and
9 Robot Framework integration tests (robot/acp_facade_wiring.robot).
Updated docs/reference/acp.md with wired operation details, service
key table, and error code taxonomy.
ISSUES CLOSED: #501
Implemented SkeletonCompressorService for ACMS context inheritance, producing
compressed context representations for propagation from parent plans to child
plans. Key design decisions and implementation details:
- SkeletonMetadata (frozen Pydantic model): records ratio, original_tokens,
compressed_tokens, and source_decision_ids for full auditability of each
compression pass. Persisted on Plan.skeleton_metadata.
- SkeletonCompressorService: stateless service accepting a list of
ContextFragment objects and a skeleton_ratio in [0.0, 1.0]. Fragments are
sorted by relevance descending with a stable secondary sort on fragment_id
to guarantee deterministic output. Token budget is original_tokens*(1-ratio);
fragments are greedily selected until budget is exhausted.
- Ratio semantics: 0.0 = no compression (pass-through), 1.0 = maximum
compression (single top fragment only), None = default 0.3.
- Integration: Plan model gains optional skeleton_metadata field exposed in
as_cli_dict() under the 'skeleton' key. Service registered in DI container
as skeleton_compressor_service (Singleton, stateless).
- Tests: 22 BDD scenarios (features/skeleton_compressor.feature) covering
ratio validation, stable ordering, metadata correctness, edge cases, and
plan model integration. 6 Robot Framework smoke tests. ASV benchmark suites
at 10/100/1000 fragment scales.
- Documentation: docs/reference/skeleton_compressor.md with ratio table,
algorithm description, metadata schema, and multi-decision plan example.
ISSUES CLOSED: #194
Implemented the Backend Abstraction Layer (BAL) for the Advanced Context
Management System, following the specification in docs/specification.md
Section ACMS > Backend Abstraction Layer and ADR-014.
Key additions:
- TextBackend protocol with search(query, scope, max_results) returning
list[TextResult], and TextResult frozen dataclass (uko_uri, content,
score, metadata fields)
- VectorBackend protocol with similarity_search(embedding, scope, top_k)
returning list[VectorResult], and VectorResult frozen dataclass
- GraphBackend protocol with sparql_query(query, scope),
get_triples(subject), and traverse(start, depth) methods returning
GraphResult frozen dataclass (triples, metadata fields)
- In-memory stub backends (InMemoryTextBackend, InMemoryVectorBackend,
InMemoryGraphBackend) that validate arguments and return empty results,
serving as development placeholders and test doubles
- DI container registration as configurable Singletons with provider
selection via override_providers()
- Behave BDD feature (35 scenarios / 83 steps) covering protocol
compliance, argument validation, result immutability, and DI resolution
- Robot Framework smoke tests (6 tests) for integration verification
- ASV benchmarks for stub query overhead and instantiation time
- Reference documentation at docs/reference/acms_backends.md
Design decisions:
- Used @runtime_checkable Protocol for structural subtyping, consistent
with existing ResourceHandler pattern
- Used frozen dataclasses (not Pydantic) for result types to minimize
overhead in the hot path of context assembly
- scope parameter typed as frozenset[str] for immutability and hashability
- Stubs registered as default Singletons; production backends swap via DI
ISSUES CLOSED: #498
Added three new built-in resource types: container-instance,
devcontainer-instance, and devcontainer-file. The devcontainer-instance
type inherits from container-instance per ADR-042 and is auto-discovered
when git-checkout or fs-directory resources contain .devcontainer/
directories per ADR-043.
Implementation includes:
- DevcontainerHandler extending BaseResourceHandler with snapshot strategy
- Auto-discovery module scanning .devcontainer/devcontainer.json and
root .devcontainer.json with JSON validation
- CLI support for devcontainer-instance and container-instance via
agents resource add with --path and --image flags
- Behave feature with 22 scenarios covering manual registration,
auto-discovery, invalid JSON handling, and protocol conformance
- Robot integration tests with 10 test cases for CLI round-trip and
DAG hierarchy validation
- ASV benchmarks measuring discovery throughput with varying subdirectory
counts, handler resolver cache performance, and result construction
- Reference documentation at docs/reference/devcontainer_resources.md
ISSUES CLOSED: #511
Add SafetyProfile domain model with configurable safety constraints
(checkpoint, human approval, cost limits, retry limits, skill
categories, sandbox requirement). Integrate into Action model with
from_config/as_cli_dict support, and persist via LifecycleActionModel
safety_profile_json column.
Include resolve_safety_profile() stub that raises NotImplementedError
for local mode, signalling that real enforcement is deferred.
Add comprehensive test coverage:
- 20 BDD scenarios in features/safety_profile.feature
- 6 Robot Framework smoke tests
- 5 ASV benchmark suites (11 timing functions)
Add docs/reference/safety_profile.md reference documentation.
ISSUES CLOSED: #332
Add --project flag to config set, config get, and config list CLI
commands, enabling per-project configuration overrides stored under
[project."<name>"] TOML tables in the global config file.
Project-scoped resolution slots between environment variable and global
levels in the ConfigService resolution chain. config list --project
shows only overrides for the named project with source annotations.
Implementation:
- ConfigService: add set_project_value() and get_project_overrides()
methods for TOML-backed project-scoped persistence and retrieval
- CLI config commands: wire --project flag through set, get, and list
subcommands; project-scoped list filters to overrides only
- Database persistence: project-scoped config stored as alternative
backend for projects not using TOML
- Documentation: update docs/reference/config_resolution.md with
project-scopable key lists, CLI examples, precedence diagram, and
non-scopable key rejection behavior
Tests:
- Behave: 12 BDD scenarios in features/config_project_scope.feature
covering set/get/list, precedence over global defaults, and
non-scopable key rejection
- Robot: 5 integration smoke tests in robot/config_project_scope.robot
for end-to-end project-scoped round-trip verification
- ASV: benchmarks/config_project_scope_bench.py measuring resolution
overhead with project scope active
All nox quality gates pass: lint, typecheck, unit_tests (7522 scenarios),
integration_tests (Config Project Scope suite passed), and coverage at
98% line rate (threshold 97%).
Closes#259
Add protocol stubs for remote server communication infrastructure:
- ServerClient: Health check and version negotiation protocol
- RemoteExecutionClient: Remote plan execution and status protocol
- AuthClient: Authentication and token management protocol
- StubServerClient/StubRemoteExecutionClient/StubAuthClient: Stub
implementations raising NotImplementedError for all methods
- ServerConnectionConfig: Validated config model (server_url, namespace,
auth_token_ref, tls_verify)
- Config keys: core.server_url, core.server_namespace, core.server_tls_verify
- CLI: agents connect <url> stub command with explicit warning
- CLI: agents info shows Server Mode (disabled/stubbed)
ISSUES CLOSED: #201
Add SubplanService for building child plans from DecisionService spawn
entries and SubplanConfig. The service validates resource scopes, merge
strategies, and max_parallel bounds before spawning.
Key additions:
- SubplanService: Orchestrates child plan creation from spawn entries
- SpawnMetadata: Persisted metadata (spawn_decision_id, parent/root
plan IDs, execution mode) for status output
- Spawn validation: Checks resource scopes, merge strategy, and
parallelism bounds before spawning
- Documentation: subplan_service.md with spawn workflow and lifecycle
ISSUES CLOSED: #197