Extend _check_providers() in system.py to report diagnostic status for
all 9 providers supported by ProviderRegistry: OpenAI, Anthropic, Google,
Azure, OpenRouter, Gemini, Cohere, Groq, and Together AI.
Previously only 4 providers (OpenAI, Anthropic, Google, OpenRouter) were
checked, leaving users of Groq, Together AI, Cohere, Azure, and Gemini
with no diagnostic feedback about their provider configuration.
Changes:
- Add Azure (AZURE_OPENAI_API_KEY), Gemini (GEMINI_API_KEY),
Cohere (COHERE_API_KEY), Groq (GROQ_API_KEY), and
Together AI (TOGETHER_API_KEY) to the provider_checks list
- Add Behave feature file with 11 scenarios covering all 9 providers
(presence, OK status when configured, WARN with recommendation when not)
ISSUES CLOSED: #3422
Implemented optional SubplanService and SubplanExecutionService wiring in PlanExecutor.__init__() (None = no-op).
- Added _spawn_subplans() helper:
- Queries spawn decisions via SubplanService.get_spawn_decisions() and calls SubplanService.spawn() for each decision.
- No-ops when there are no spawn decisions.
- Added _execute_subplans() helper:
- Delegates to SubplanExecutionService.execute_all() to run spawned subplans, handling both sequential and parallel groups as dictated by decisions.
- Added _apply_subplan_results_to_plan() helper:
- Updates parent plan status tracking when child subplans fail.
- Annotates error_details with failed_subplan_ids when appropriate.
- Integrated spawning and execution into existing flow:
- Called _spawn_subplans() and _execute_subplans() from both _run_execute_with_runtime() and _run_execute_with_stub() after actor completion.
- Introduced PlanExecutor properties:
- subplan_service and subplan_execution_service for external wiring and testability.
- Added tests and scenarios:
- Behave feature file with 6 scenarios covering subplan_spawn, subplan_parallel_spawn, no-op, and failure tracking.
- Robot Framework integration test suite with 6 end-to-end subplan spawning test cases.
Key design decisions
- Optional services (None = no-op) to maintain backward compatibility with existing deployments.
- Subplan spawning is a no-op when no spawn decisions exist, avoiding unnecessary work.
- Parent plan error_details is annotated with failed_subplan_ids when a child subplan fails to aid debugging and traceability.
- Both runtime and stub execute paths share the same spawning logic to ensure consistent behavior across execution modes.
ISSUES CLOSED: #3561
- docs/reference/plan_cli.md: add note about legacy/v3 plan workflow
mixing being disallowed (introduced in v3.8.0, issue #1577)
- docs/reference/uko_runtime.md: document v3.8.0 provenance tracking
(sourceResource, validFrom, isCurrent on typed triples) and revision
chain for temporal queries across indexing runs (issue #891)
- docs/reference/decision_correction.md: add CorrectionAttemptRecord
section documenting the correction_attempts table, state lifecycle,
repository API, and usage examples (issue #920)
- docs/modules/uko-provenance.md: new module guide for UKO provenance
tracking covering purpose, how provenance is attached, revision chain
mechanics, query patterns, persistence format, BDD coverage, and gotchas
Adds comprehensive bug prevention safeguards to the issue-implementor agent
definition to prevent critical failure where PR priority gate logic was not
correctly implemented, resulting in 37 PRs being incorrectly skipped.
Changes made:
- Added explicit warnings never to use `limit` parameter when fetching PRs
- Added comprehensive logging during PR analysis with progress indicators
- Added mandatory verification that total analyzed PRs equals total fetched
- Added PR-first rule enforcement logging showing when issue work blocked/allowed
- Added error detection for violations of absolute PR priority rule
- Added historical bug documentation section with prevention measures
This ensures future instances will:
- Always fetch ALL open PRs (never use sampling/limits)
- Log verification counts during analysis
- Explicitly enforce the absolute PR-first priority rule
- Detect and report any violations of the priority rule
The bug caused the supervisor to incorrectly conclude "no PRs need work"
when 37 out of 50 open PRs actually required automated attention, violating
the fundamental PR-FIRST rule that blocks all issue work until every PR
has an active worker.
ISSUES CLOSED: #3377
Implements the spec-required JSON/YAML output envelope for all CLI commands
that use format_output(). The envelope structure is:
{
"command": "<command that was run>",
"status": "ok" | "warn" | "error",
"exit_code": 0,
"data": { ... command-specific payload ... },
"timing": { "duration_ms": 123 },
"messages": [{ "level": "ok", "text": "..." }]
}
Changes:
- Add _build_envelope() helper to construct the spec-required envelope
- Add optional command, status, exit_code, messages parameters to format_output()
- Wrap json/yaml output in the envelope; plain/table/rich/color unchanged
- Add timing measurement (duration_ms) to all json/yaml outputs
- Add new BDD feature file (cli_json_envelope.feature) with 14 scenarios
testing envelope field presence, values, and data payload
- Update 14 existing step files to unwrap the envelope when checking
specific data keys (backward-compatible via _unwrap_envelope() helper)
Closes#3431
Resolves issue #3443: the `agents plan rollback` confirmation prompt was
missing the checkpoint's descriptive label, relative creation time, and
side-effects count (decisions invalidated / child plans cancelled).
Changes:
- Added `_format_relative_time(dt)` helper to produce human-readable
relative timestamps (e.g. "42 minutes ago", "2 hours ago").
- In `rollback_plan`, moved `get_container()` / `checkpoint_service()`
before the confirmation block so checkpoint metadata is available.
- When `--yes` is not passed, `svc.get_checkpoint()` is called to fetch
the checkpoint label (`metadata.reason`) and creation time.
- Decisions created after the checkpoint are counted via
`decision_service.list_decisions()`; `subplan_spawn` /
`subplan_parallel_spawn` decisions are counted as child plans.
- Side-effects line is printed before the prompt when counts > 0.
- Falls back to the original simple prompt if checkpoint metadata
cannot be fetched (e.g. checkpoint not found).
- Updated existing rollback mock helpers to wire `get_checkpoint` and
`decision_service` properly.
- Added 3 new Behave scenarios covering label display, side-effects
display, and fallback behaviour.
Closes#3443
Implements the spec-required JSON envelope for `agents plan execute --format json`.
Previously, the command returned the raw plan domain model dict via
`_plan_spec_dict()`, which was missing the sandbox, worker, started,
attempt, strategy_summary, and progress fields required by the spec.
Changes:
- Add `_execute_output_dict(plan, started_at, duration_ms)` function that
builds the spec-required execute output envelope with:
- Top-level envelope: command, status, exit_code, data, timing, messages
- data.sandbox: strategy, path, branch, status (derived from sandbox_refs)
- data.worker: execution_actor or 'local/executor' fallback
- data.started: HH:MM:SS from execute_started_at timestamp
- data.attempt: from plan.identity.attempt
- data.strategy_summary: decisions, invariants, planned_child_plans,
estimated_files, risk (from estimation_result when available)
- data.progress: 4-step list with label/status derived from plan state
- Update `execute_plan()` to track wall-clock start time and use
`_execute_output_dict()` instead of `_plan_spec_dict()` for non-rich output
- Add BDD tests verifying the spec-required envelope structure, sandbox
strategy field, and progress list label/status fields
ISSUES CLOSED: #3435
Fixes three deviations from docs/specification.md in the agents session show
rich output Session Summary panel:
1. Renamed 'Session ID:' label to 'ID:' to match spec exactly.
2. Removed 'Namespace:' field which is not part of the spec.
3. Added 'Automation:' field sourced from session.metadata['automation_profile'],
defaulting to '(none)' when not set.
4. Field order now matches spec: ID → Actor → Messages → Created → Updated → Automation.
Updated features/session_cli.feature to assert the corrected field labels are
present ('ID:', 'Actor:', 'Messages:', 'Created:', 'Updated:', 'Automation:')
and that the removed fields ('Session ID:', 'Namespace:') are absent.
Added 'the session CLI output should not contain' step definition to
features/steps/session_cli_steps.py to support the new negative assertions.
ISSUES CLOSED: #3040
- docs/api/tui.md: Document ShellDangerLevel, DangerousPattern, DEFAULT_PATTERNS,
DangerousPatternDetector, ShellSafetyService, and SafetyCheckResult with
full API reference, parameter tables, and usage examples
- docs/architecture.md: Add Invariant Reconciliation section covering the
builtin/invariant-reconciliation actor, four-scope algorithm, failure
behaviour, and DI registration
- README.md: Add Invariant Reconciliation, TUI shell danger detection, and
UKO provenance tracking to the Highlights section
ISSUES CLOSED: #3377
- Promote [Unreleased] CHANGELOG entries to [3.8.0] (2026-04-05)
- Add Shell Danger Detection section to docs/api/tui.md covering
ShellDangerLevel, DangerousPattern, ShellSafetyService, and
SafetyCheckResult with full API reference and usage examples
- Add InvariantService section to docs/api/core.md documenting
the new DI-registered singleton, its methods, and emitted events
- Update docs/architecture.md Plan Lifecycle section to document
invariant reconciliation as a phase transition gate
- Update README.md Highlights with shell danger detection, inline
permission questions, invariant reconciliation, UKO provenance
tracking, and JSON-RPC 2.0 A2A wire format
- Create docs/modules/shell-safety.md with full module guide
covering purpose, key classes, built-in patterns, custom pattern
registration, TUI integration, and testing guidance
ISSUES CLOSED: #1003#997#1391#1004#891#1501#1577#1941#2334
- Fix session adoption logic with correct title patterns for both
worker-issue-impl and worker-pr-fix sessions
- Add PR worker adoption to coordinate orphaned PR fix workers
- Enhance worker verification with comprehensive status checking,
retry logic, and proper error handling
- Add defensive programming with worker count enforcement and
state validation to prevent coordination drift
- Improve JSON parsing with safe error handling throughout
- Add periodic maintenance cycle (every 5 iterations) for
worker state validation and limit enforcement
These fixes resolve the core issue where the implementation pool
supervisor was not properly coordinating 40+ existing workers,
causing worker count to exceed the designed limit of 32.
Fixed three critical issues in the CleverAgents autonomous system:
1. Worker Management: Enhanced issue-implementor health signaling to report
detailed worker listings with session IDs and status. Added worker
verification after dispatch to ensure workers actually start. Improved
idle detection with aggressive work discovery when capacity is available.
2. PR Priority: Fixed PR work detection to include orphaned PRs from
completed issues. Added absolute PR priority enforcement that blocks
all issue work when any PR needs attention. Fixed worker dispatch
prompts to clearly indicate operation mode (pr-fix vs issue-impl).
3. Bot Approval Requirements: Implemented single approval merging for bot
PRs. Bot PRs (containing 'Automated by CleverAgents Bot') now merge
with 1 approval while human PRs still require 2 per CONTRIBUTING.md.
Updated branch protection to required_approvals: 1 with logic in agents
to enforce the distinction. Added detection for approved-but-stuck PRs.
These changes ensure the system operates at maximum efficiency with proper
parallelism while maintaining quality gates through CI and code review.
Replace validate_assignment=True with frozen=True on Invariant,
InvariantViolation, InvariantEnforcementRecord, and InvariantSet models
to enforce the value-object immutability contract required by the spec.
Redesign InvariantService.remove_invariant() to use model_copy(update=
{'active': False}) instead of direct field mutation, since frozen models
raise ValidationError on assignment.
Fix invariant_reconciliation_actor_steps.py step that mutated
inv.non_overridable = True to construct the Invariant directly with
non_overridable=True at creation time.
Add BDD scenarios covering:
- Immutability contract: mutation raises error on all three models
- Hashability: frozen Pydantic v2 models are hashable
- Soft-delete copy-and-replace: removed invariant is a new object
All 266 scenarios pass. Lint and typecheck pass.
ISSUES CLOSED: #3116
Fixes issue #3440: agents session show JSON output uses wrong field names and wrong data types.
- Add LinkedPlan value object with plan_id, phase, state fields
- Add automation field to Session domain model
- Rewrite as_cli_dict() with spec-compliant field names in session_summary wrapper
- Use 'text' key in recent_messages items
- Replace linked_plan_ids with linked_plans objects
- Format estimated_cost as string (e.g. '$0.0184')
- Update session show rich output with spec-compliant labels
- Update tests to assert new field names
ISSUES CLOSED: #3440
Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Replaces hardcoded 0 values in the Impact panel of `agents actor remove` with real DB-backed counts for sessions, active plans, and actions referencing the removed actor.
ISSUES CLOSED: #3420
Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
- Implemented Updated column in the plan list rich output by extending
lifecycle_list_plans() in src/cleveragents/cli/commands/plan.py.
The column is inserted after the existing Project column and before
Elapsed to maintain logical grouping.
- Added updated_str using plan.timestamps.updated_at.strftime('%Y-%m-%d %H:%M')
for a human-friendly timestamp in local time.
- Added three Behave scenarios in features/plan_cli_spec_alignment.feature
to assert presence of Name, Updated, and Invariants columns.
- Added 'When I run plan list with no filters' step definition.
- Added list_columns() function to robot/helper_plan_cli_spec.py verifying
all three columns with partial header checks due to terminal truncation.
- Added 'Plan List Rich Output Includes Required Columns' test case to
robot/plan_cli_spec.robot.
ISSUES CLOSED: #2611
Add a 'State' column to the 'agents resource list' rich table output that
shows the current lifecycle state for devcontainer-instance and
container-instance resources. For newly-discovered devcontainers the state
displays as 'detected (not built)'; running, stopped, and failed states are
also shown.
Changes:
- Add _get_lifecycle_state_str() helper that queries get_lifecycle_tracker()
for container resource types and returns a human-readable state string
- Add 'State' column to the rich table in resource_list()
- Show warning banner '⚠ Devcontainer detected at ...' for resources in
the detected state, matching the spec output for agents resource add
- Update _resource_dict() to include 'lifecycle_state' field in JSON/YAML
output (null for non-container resources)
- Add BDD feature file and step definitions covering all lifecycle states,
warning banner behaviour, and JSON output
ISSUES CLOSED: #2596
- Replace ctrl+tab with ctrl+t for preset cycling in _CONTEXT_ITEMS Main Screen
context, matching the actual BINDINGS registered in app.py
- Remove the tab/Cycle to next persona entry from Main Screen context since
no such binding exists in app.BINDINGS (tracked separately in #3338)
- Add Behave BDD scenarios asserting that help panel keybindings match the
actual registered BINDINGS: ctrl+t present, ctrl+tab absent, no stale tab
entry for persona cycling
- Add step definition for 'should not contain' assertion to support the new
negative-assertion scenarios
Resolves the double-inconsistency where users following the help panel
instructions (ctrl+tab) would press the wrong key and get no response.
ISSUES CLOSED: #3444
Implements the three Rich panels required by specification.md §"agents session export"
(lines 1987–2115) that were missing from the export_session() command.
Changes:
- Add _render_export_panels() helper that renders three spec-required panels:
* "Session Export" panel: session ID, output path, message count, file size, format
* "Contents" panel: messages, plan references, metadata keys, actor config, schema version
* "Integrity" panel: checksum (sha256:xxxx...xxxx), encrypted flag
- Fix success message from "Session exported to {output}" to "Export completed"
- Fix stdout export path to also render Rich panels (previously only printed raw JSON)
- Keep --format and --force options (useful extensions, do not break spec compliance)
- Update Behave scenarios in features/session_cli.feature to verify panel rendering
- Update Robot Framework helper and test file with new export panel assertions
ISSUES CLOSED: #3424
Extend DevcontainerDiscoveryResult and discover_devcontainers() to scan
.devcontainer/<name>/devcontainer.json patterns (one subdirectory level)
in addition to the existing fixed paths. Each named configuration produces
a distinct result with config_name set to the subdirectory name (e.g.
'api', 'frontend'). Root-level configs retain config_name=None.
- Replace _SCAN_PATHS with _FIXED_SCAN_PATHS for root-level configs
- Add glob-based scan of .devcontainer/<name>/devcontainer.json
- Add config_name: str | None attribute to DevcontainerDiscoveryResult
- Validate config_name (must be non-empty str or None)
- Add 8 new Behave scenarios covering named, multiple, mixed, empty cases
- Add 4 new Robot Framework integration tests for named config discovery
- All existing tests continue to pass (no regression)
ISSUES CLOSED: #2615
Previously, ProviderRegistry.create_ai_provider() dispatched to dedicated
provider classes only for Google and OpenRouter. For OpenAI and Anthropic,
execution fell through to the generic LangChainChatProvider factory, leaving
OpenAIChatProvider and AnthropicChatProvider as dead code in production.
This commit:
- Adds ProviderType.OPENAI dispatch branch in create_ai_provider() to
instantiate OpenAIChatProvider with the configured API key and model
- Adds ProviderType.ANTHROPIC dispatch branch in create_ai_provider() to
instantiate AnthropicChatProvider with the configured API key and model
- Both branches raise ValueError with the missing env var name when the
API key is not configured, consistent with Google and OpenRouter branches
- Updates src/cleveragents/providers/llm/__init__.py to export all four
dedicated provider classes (OpenAIChatProvider, AnthropicChatProvider,
GoogleChatProvider, OpenRouterChatProvider)
- Updates provider_registry_coverage.feature to assert that create_ai_provider
returns OpenAIChatProvider for openai and AnthropicChatProvider for anthropic
- Adds new scenarios for Anthropic dispatch and missing-key error paths for
both OpenAI and Anthropic
- Updates the 'AI provider exposes working llm factory' scenario to use groq
(which still goes through the generic LangChainChatProvider path) since
OpenAI now uses the dedicated class
- Adds step definitions for OpenAIChatProvider and AnthropicChatProvider
isinstance assertions
Closes#3427
Replace the flat `parent_types` membership check in
`BindingResolutionService._is_type_compatible` with a call to
`self._registry.is_subtype_of()`, which uses
`resolve_inheritance_chain()` from `cleveragents.resource.inheritance`
to walk the full ADR-042 inheritance chain.
Previously, a tool requiring type `container-instance` would fail to
bind a `devcontainer-instance` resource because the check only looked
at the immediate `parent_types` list rather than traversing the full
chain. The fix ensures multi-level inheritance (e.g.
`local/special-dev-container` → `devcontainer-instance` →
`container-instance`) is correctly resolved for contextual, static,
and parameter bindings.
Changes:
- `binding_resolution_service.py`: `_is_type_compatible` now delegates
to `registry.is_subtype_of()`; removed unused `ResourceTypeSpec`
import.
- `consolidated_binding_resolution.feature`: 4 new scenarios covering
2-level chain, 3-level chain, unrelated-type rejection, and static
binding via inheritance chain.
- `binding_resolution_steps.py`: mock registry exposes
`is_subtype_of()` backed by the real inheritance engine; new step
definitions for inheritance chain setup.
ISSUES CLOSED: #2929
Add label requirements to all 16 supervisor launch prompts in
product-builder.md so that any tracking issues created by supervisors
include the required Type/Automation, State/In Progress, and
Priority/Medium labels from creation.
This eliminates the persistent label compliance gap reported by the
system watchdog, where supervisor-created tracking issues consistently
missed required State/ and Priority/ labels.
ISSUES CLOSED: #3070
Per JSON-RPC 2.0 specification (Section 5.1), error codes must be integers.
This commit fixes the protocol compliance defect where A2aErrorDetail.code
was typed as str and error constants were string literals.
Changes:
- src/cleveragents/a2a/models.py: Change A2aErrorDetail.code from str to int;
update field_validator to only validate 'message' (code no longer needs
non-empty string check; Pydantic enforces int type)
- src/cleveragents/a2a/errors.py: Change all error code constants from string
literals to JSON-RPC 2.0 integer codes per docs/reference/a2a.md taxonomy:
NOT_FOUND = -32001, AUTH_ERROR = -32002, FORBIDDEN = -32003,
INVALID_STATE = -32004, PLAN_ERROR = -32008, CONFIGURATION_ERROR = -32009,
VALIDATION_ERROR = -32602, INTERNAL_ERROR = -32603
Update map_domain_error() return type from tuple[str, str] to tuple[int, str]
- features/steps/a2a_facade_steps.py: Update A2aErrorDetail construction to
map symbolic string names to integer codes via _CODE_MAP
- features/steps/a2a_facade_wiring_steps.py: Update error code assertion to
map symbolic names to integers for comparison
- features/steps/a2a_facade_coverage_boost_steps.py: Same as above
- features/steps/a2a_jsonrpc_wire_format_steps.py: Update all A2aErrorDetail
constructions and JSON-RPC dict payloads to use integer codes
- robot/helper_a2a_facade_wiring.py: Update wired_error_mapping() to compare
against integer codes
- robot/helper_a2a_jsonrpc_wire_format.py: Update response_error_wire_format()
to use integer code -32001 instead of string 'NOT_FOUND'
Wire format now produces {"code": -32001, ...} instead of {"code": "NOT_FOUND", ...},
making it compliant with JSON-RPC 2.0 and interoperable with standards-conformant clients.
ISSUES CLOSED: #2746
_get_tool_registry_service in cli/commands/validation.py was manually
constructing the full ToolRegistryService dependency graph (create_engine,
sessionmaker, ToolRegistryRepository, ValidationAttachmentRepository) instead
of delegating to the DI container. This duplicated wiring logic that belongs
exclusively in the container and made the function harder to test.
Changes:
- Add _build_tool_registry_service() builder function to container.py
following the established _build_skill_service/_build_session_service pattern
- Register tool_registry_service as a Singleton provider in the Container class
- Refactor _get_tool_registry_service() to delegate to
container.tool_registry_service() — a one-liner consistent with
_get_skill_service() in cli/commands/skill.py
- Add TDD Behave feature (tdd_di_tool_registry_service.feature) with two
scenarios: (1) function delegates to container, (2) container exposes the
provider — both scenarios were failing before this fix
- Update validation_cli_uncovered_branches_steps.py to match the new
container-delegation pattern (mock container.tool_registry_service()
instead of container.database_url())
ISSUES CLOSED: #3006
Add plain text (txt) export format to the TUI /session:export command.
- Add Session.as_export_plain_text() domain method that produces a
human-readable plain text transcript without Markdown formatting
- Update TuiCommandRouter._session_export() to accept 'txt' as a valid
format, building the plain text content via as_export_plain_text()
- Update the invalid-format error message to include 'txt' as a valid
option alongside 'json' and 'md'
- Add BDD scenarios covering plain text export via TUI command and
domain model, including with-messages and no-messages cases
- Add corresponding step definitions for the new BDD scenarios
The plain text format uses a simple separator-based layout:
Session: <id>
Actor: <actor>
...
----------------------------------------
[0] USER (timestamp):
message content
----------------------------------------
ISSUES CLOSED: #3036
Update SlashCommandOverlay.set_commands() to accept list[SlashCommandSpec]
instead of list[str], and render each entry as aligned columns:
/command-name Description text
Changes:
- slash_command_overlay.py: update set_commands() signature to accept
list[SlashCommandSpec]; render name + description with aligned padding
using _COMMAND_COL_WIDTH = 28 characters for the name column
- slash_catalog.py: add slash_command_specs() helper returning all specs
- app.py: switch on_mount() to call slash_command_specs() instead of
slash_command_names() so full spec objects are passed to the overlay
- features/tui_slash_command_overlay_coverage.feature: add scenario
verifying description rendering; update existing scenarios to use
SlashCommandSpec objects via _make_specs() helper
- features/steps/tui_slash_command_overlay_coverage_steps.py: update
step implementations to build SlashCommandSpec objects from CSV names
- features/tui_slash_overlay_descriptions.feature: new feature file with
BDD scenarios covering description rendering and @tdd_expected_fail
capture of the pre-fix name-only behaviour
- features/steps/tui_slash_overlay_descriptions_steps.py: step defs for
the new feature file
- robot/tui_smoke.robot: add Slash Command Overlay Renders Descriptions
integration test verifying descriptions appear in rendered overlay
ISSUES CLOSED: #3437
The tool_type parameter in ToolRegistry.list_tools() was explicitly
silenced with '_ = tool_type', making it a no-op. Both
'agents tool list --type validation' and 'agents tool list --type tool'
returned the full unfiltered tool list.
Changes:
- src/cleveragents/tool/runtime.py: Add tool_type: Literal['tool',
'validation'] field to ToolSpec (default 'tool') so the registry
has a discriminator to filter on.
- src/cleveragents/tool/registry.py: Remove '_ = tool_type' no-op and
implement actual filter: specs = [s for s in specs if s.tool_type == tool_type].
Update docstring to reflect the parameter is now active.
- features/consolidated_tool.feature: Add 7 comprehensive Behave
scenarios covering all filter combinations (tool, validation, None,
default type, exclusion).
- features/steps/tool_runtime_steps.py: Add step definition for
registering a ToolSpec with an explicit tool_type.
- robot/helper_tool_cli.py: Add tool_list_type_tool() and
tool_list_type_validation() helper functions that verify the CLI
passes tool_type through to the service layer.
- robot/tool_cli.robot: Add two Robot test cases for
'tool list --type tool' and 'tool list --type validation'.
The CLI handler (cli/commands/tool.py) and database repository
(infrastructure/database/repositories.py) already passed tool_type
through correctly — no changes needed there.
ISSUES CLOSED: #2974