Skip to content

feat(#735): Agent-first architecture — CLI, abilities, runtime, and Admin UI#763

Merged
chubes4 merged 5 commits intomainfrom
feature/735-agent-first-cli
Mar 9, 2026
Merged

feat(#735): Agent-first architecture — CLI, abilities, runtime, and Admin UI#763
chubes4 merged 5 commits intomainfrom
feature/735-agent-first-cli

Conversation

@chubes4
Copy link
Member

@chubes4 chubes4 commented Mar 9, 2026

Summary

Implements the agent-first architecture (#735) — making agent_id the primary scoping key across CLI, abilities, runtime, and Admin UI. All 5 logical PRs are on this branch.

Key discovery: The DB schema, REST scoping, and most Admin UI agent filtering were already built. This PR fills the remaining gaps to make agent_id a first-class citizen everywhere.

Commits

1. --agent flag across all CLI commands

  • AgentResolver class: resolve(), resolveContext(), buildScopingInput()
  • PipelinesCommand, FlowsCommand, JobsCommand, MemoryCommand all use --agent for agent-scoped queries
  • 9 unit tests

2. Agent CRUD CLI + abilities

  • agents create/show/delete + agents access grant/revoke/list CLI subcommands
  • AgentAbilities: createAgent(), getAgent(), deleteAgent() with full validation
  • 13 unit tests

3. Agent context propagation in abilities

  • CreatePipelineAbility: agent_id in schema, stored in DB, cascaded to auto-created flows
  • CreateFlowAbility: agent_id in schema, stored in DB
  • DuplicatePipelineAbility: carries agent_id from source, allows override, cascades to flows
  • AgentMemoryAbilities: all 4 schemas document agent_id
  • 15 unit tests

4. ExecutionContext carries agent identity

  • ExecutionContext: $agent_id property, getAgentId() with engine data fallback
  • fromFlow() / fromConfig() extract agent_id; log() includes it in context
  • EngineData::getAgentId() reads from job snapshot
  • withHandlerType() / withJobId() preserve agent_id through clone
  • 12 unit tests

5. Chat sessions agent scoping (last Admin UI gap)

  • DB: get_user_sessions() and get_user_session_count() accept optional agent_id
  • ListChatSessionsAbility: agent_id in input schema, passed through to DB
  • REST /chat/sessions: agent_id route arg, resolved via PermissionHelper::resolve_scoped_agent_id()
  • chat.js: useChatSessions() switched from raw apiFetch to shared client so the agent interceptor auto-injects agent_id

Test results

845 tests, 0 failures (27 new tests added across PRs 1-4)

Files changed

New files

  • inc/Cli/AgentResolver.php
  • tests/Unit/Cli/AgentResolverTest.php
  • tests/Unit/Abilities/AgentAbilitiesTest.php
  • tests/Unit/Abilities/AgentContextPropagationTest.php
  • tests/Unit/Core/ExecutionContextAgentTest.php

Modified

  • inc/Cli/Commands/PipelinesCommand.php
  • inc/Cli/Commands/Flows/FlowsCommand.php
  • inc/Cli/Commands/JobsCommand.php
  • inc/Cli/Commands/MemoryCommand.php
  • inc/Cli/Commands/AgentsCommand.php
  • inc/Abilities/AgentAbilities.php
  • inc/Abilities/AgentMemoryAbilities.php
  • inc/Abilities/Pipeline/CreatePipelineAbility.php
  • inc/Abilities/Pipeline/DuplicatePipelineAbility.php
  • inc/Abilities/Flow/CreateFlowAbility.php
  • inc/Abilities/Chat/ListChatSessionsAbility.php
  • inc/Api/Chat/Chat.php
  • inc/Core/ExecutionContext.php
  • inc/Core/EngineData.php
  • inc/Core/Database/Chat/Chat.php
  • inc/Core/Admin/Pages/Pipelines/assets/react/queries/chat.js

Closes #735

chubes4 added 2 commits March 9, 2026 16:51
Add AgentResolver for --agent=<slug|id> resolution, parallel to
UserResolver. Agent scoping takes precedence over --user when both
are provided. Updated commands:

- PipelinesCommand: --agent scoping for list/get
- FlowsCommand: --agent scoping for list/get
- JobsCommand: --agent scoping for list
- MemoryCommand: --agent scoping for read/write/search/sections/daily/files

AgentResolver.buildScopingInput() provides the bridge: resolves
--agent first, falls back to --user, returns empty for unscoped.

9 new tests for AgentResolver. All 805 tests pass, lint clean.
Add full agent lifecycle management to CLI and Abilities:

CLI commands (wp datamachine agents):
- create <slug> --name --owner --config: create new agent with owner access
- show <slug|id>: display agent details, config, access grants
- delete <slug|id> [--delete-files]: remove agent and access grants
- access grant/revoke/list: manage agent RBAC (admin/operator/viewer)

AgentAbilities additions:
- createAgent(): creates agent, bootstraps owner access, ensures directory
- getAgent(): retrieves agent with config, access grants, directory info
- deleteAgent(): removes agent, access grants, optional file cleanup

Handles json_decode safely when DB layer pre-decodes agent_config.
13 new tests covering all CRUD operations. All 818 tests pass.
@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Homeboy Results — data-machine

Lint

⚡ Scope: changed files only

lint (changed files only)

  • PHPCS: LINT SUMMARY: 1 errors, 9 warnings
  • Fixable: 6 | Files with issues: 2 of 16
  • PHPStan: PHPSTAN SUMMARY: 206 errors at level 5

Test

⚡ Scope: changed files only

test (changed files only)

  • PHPCS: LINT SUMMARY: 69 errors, 105 warnings
  • Fixable: 146 | Files with issues: 24 of 369
Top violations
  WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine    51
  Generic.Formatting.MultipleStatementAlignment.NotSameWarning    49
  WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned    41
  Universal.Operators.DisallowShortTernary.Found              6
  WordPress.DB.PreparedSQL.NotPrepared                        4
- PHPStan: PHPSTAN SUMMARY: 206 errors at level 5 - Tests: 740, Assertions: 2699, Skipped: 3.

Audit

⚡ Scope: changed files only

audit (changed files only)

  • Actionable audit summary:
  • Alignment score: 0.763
  • Severity counts: info: 1697, unknown: 61, warning: 60
  • Drift increased: no
  • Outliers in current run: 61
  • Parsed outlier entries: 61
  • Top actionable findings:
    1. tests/Unit/Abilities/AgentContextPropagationTest.php — missing_method — Missing method: tear_down
    2. tests/Unit/Abilities/AgentAbilitiesTest.php — missing_method — Missing method: tear_down
    3. inc/Abilities/Chat/ChatSessionHelpers.php — naming_mismatch — Helper-like name does not match convention suffix 'Ability': ChatSessionHelpers
    4. tests/Unit/Cli/AgentResolverTest.php — missing_method — Missing method: set_up
    5. tests/Unit/Cli/AgentResolverTest.php — missing_import — Missing import: WP_UnitTestCase
Tooling versions
  • Homeboy CLI: homeboy 0.73.0
  • Extension: wordpress from https://github.com/Extra-Chill/homeboy-extensions
  • Extension revision: unknown
  • Action: Extra-Chill/homeboy-action@v1

Homeboy Action v1

chubes4 added 3 commits March 9, 2026 17:11
Add agent_id to input schemas and execution logic for:
- CreatePipelineAbility: stores agent_id, cascades to auto-created flows
- CreateFlowAbility: stores agent_id in DB when provided
- DuplicatePipelineAbility: carries agent_id from source or allows override
- AgentMemoryAbilities: all 4 schemas now document agent_id alongside user_id

The DB layer already accepts agent_id — these changes close the gap
between the CLI (PR #763) and the abilities/REST layer so callers
can scope resources to agents end-to-end.

15 new tests verify schema registration and DB propagation.
Add agent_id to ExecutionContext (new private property) and EngineData:

- ExecutionContext::fromFlow() accepts optional agent_id parameter
- ExecutionContext::fromConfig() extracts agent_id from config array
- ExecutionContext::getAgentId() returns explicit agent_id or falls
  back to engine data's job context
- ExecutionContext::log() includes agent_id in log context when present
- EngineData::getAgentId() reads from job snapshot's agent_id field
- withHandlerType/withJobId preserve agent_id through clone

Agent identity now flows end-to-end: flow DB → job creation →
engine snapshot → ExecutionContext → handlers + logging.

12 new tests verify all factory methods, fallbacks, and clone behavior.
… gap

Chat sessions were the only Admin UI page bypassing agent filtering.
The list endpoint, ability, DB layer, and client-side query now all
support agent_id so the AgentSwitcher filters chat sessions like it
already does for pipelines, flows, jobs, and logs.

- DB: get_user_sessions() and get_user_session_count() accept optional agent_id
- ListChatSessionsAbility: agent_id in input schema, passed to DB
- REST /chat/sessions: agent_id route arg, resolved via PermissionHelper
- chat.js: useChatSessions() switched from raw apiFetch to shared client
  so the agent interceptor auto-injects agent_id on every list request
@chubes4 chubes4 changed the title feat(#735): agent-first CLI — --agent flag, CRUD, and access management feat(#735): Agent-first architecture — CLI, abilities, runtime, and Admin UI Mar 9, 2026
@chubes4 chubes4 merged commit befe6a5 into main Mar 9, 2026
3 checks passed
@chubes4 chubes4 deleted the feature/735-agent-first-cli branch March 9, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Agent-first architecture: agent_id as primary scoping key for pipelines, flows, jobs

1 participant