Skip to content

Commit 197b2b3

Browse files
authored
Merge pull request #299 from Extra-Chill/feat/298-routing-agents-md
Refine generated WordPress and Homeboy routing
2 parents 07ee0b2 + 169000b commit 197b2b3

3 files changed

Lines changed: 92 additions & 517 deletions

File tree

lib/agents-md-guidance.sh

Lines changed: 46 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,13 @@
1515
# agents_md_guidance_register <section_id> <priority> <label> <description> <content>
1616
# agents_md_guidance_unregister <section_id>
1717
# agents_md_guidance_sync_wordpress_agent_boundaries
18-
# agents_md_guidance_sync_homeboy_cli # presence-gated on `command -v homeboy`
19-
# agents_md_guidance_register_homeboy_cli # writes a LIVE-enumeration PHP block
18+
# agents_md_guidance_sync_homeboy_cli # presence-gated on an executable Homeboy binary
19+
# agents_md_guidance_register_homeboy_cli # writes a live presence-checked PHP block
2020
# agents_md_guidance_unregister_homeboy_cli
2121
#
22-
# The homeboy-cli section is generated LIVE at AGENTS.md compose time: the
23-
# mu-plugin callback shells out to `homeboy --help` on every compose (cached
24-
# briefly on the binary mtime + version), so a `homeboy upgrade` converges on
25-
# the next compose without requiring a wp-coding-agents sync. See issue #254.
22+
# The homeboy-cli callback checks the current PATH at AGENTS.md compose time, so
23+
# an unavailable binary contributes no stale guidance. The live CLI help remains
24+
# authoritative for Homeboy's complete command surface.
2625
#
2726
# Honors DRY_RUN (logs intent, makes no changes).
2827

@@ -221,27 +220,31 @@ agents_md_guidance_unregister() {
221220
agents_md_guidance_sync_wordpress_agent_boundaries() {
222221
local source_content abilities_content
223222

224-
source_content='## WordPress Source (Read-Only Reference)
223+
source_content='## WordPress Source (Direct Reference, Read-Only)
225224
226-
These directories are **read-only reference material** — grep and read them to understand code, but never edit them directly.
225+
Use the installed WordPress source to verify core APIs, hooks, conventions, and runtime behavior instead of relying on assumptions. Search and read these directories directly when working on WordPress:
227226
228227
- `wp-content/plugins/` — plugin source (read-only)
229228
- `wp-content/themes/` — theme source (read-only)
230-
- `wp-includes/` — WordPress core (read-only)'
229+
- `wp-includes/` — WordPress core (read-only)
230+
231+
These paths are **read-only references**. Make code changes in the configured managed workspace, not in the installed source tree.'
231232

232233
abilities_content='## Abilities
233234
234235
WordPress Abilities are the universal tool surface. Plugins expose abilities through the active runtime, REST API, MCP, and chat.
235236
236-
Inspect the active runtime tool listings and plugin-specific `--help` output before assuming what is available.'
237+
**Default routing**
238+
- Use abilities exposed by the active runtime when they match the task.
239+
- Inspect the active runtime tool listings and plugin-specific `--help` before assuming a capability or argument is available.'
237240

238241
AGENTS_MD_GUIDANCE_FRESHNESS=static \
239242
AGENTS_MD_GUIDANCE_CONDITIONS='Registered by wp-coding-agents on managed WordPress coding-agent installations.' \
240243
agents_md_guidance_register \
241244
'wordpress-source' \
242245
1 \
243246
'WordPress Source' \
244-
'Generic boundaries for installed WordPress source.' \
247+
'Direct-reference and read-only boundaries for installed WordPress source.' \
245248
"$source_content"
246249

247250
AGENTS_MD_GUIDANCE_FRESHNESS=static \
@@ -255,21 +258,16 @@ Inspect the active runtime tool listings and plugin-specific `--help` output bef
255258
}
256259

257260
# ---------------------------------------------------------------------------
258-
# Homeboy CLI command map (issues #208, #254)
261+
# Homeboy routing guidance (issues #208, #254, #298)
259262
#
260263
# homeboy is an OPTIONAL host binary. The map is strictly presence-gated:
261264
# - present (`command -v homeboy` succeeds) -> emit a first-class section
262-
# whose callback ENUMERATES `homeboy --help` LIVE at AGENTS.md compose
263-
# time. A `homeboy upgrade` therefore converges on the next compose,
264-
# with no wp-coding-agents sync required (the #254 trigger gap).
265+
# whose callback verifies Homeboy is still present at compose time.
265266
# - absent -> complete no-op (unregister any stale section, emit nothing).
266267
#
267-
# The command list is NEVER baked into the mu-plugin as a frozen string;
268-
# the previous static-bake design was the #254 defect. The PHP helper that
269-
# performs the live enumeration is shipped inline in the homeboy-cli
270-
# section block (see _agents_md_guidance_render_homeboy_live_block), with
271-
# a WP transient cache keyed on the homeboy binary path + mtime + version
272-
# so steady-state compiles are free and the cache self-heals on upgrade.
268+
# The generated section intentionally contains routing, ownership, safety, and
269+
# discovery guidance rather than a copy of `homeboy --help`. The live CLI is the
270+
# authoritative command map.
273271
# ---------------------------------------------------------------------------
274272

275273
# agents_md_guidance_sync_homeboy_cli
@@ -279,7 +277,9 @@ Inspect the active runtime tool listings and plugin-specific `--help` output bef
279277
# agree on presence. When homeboy is present, registers a LIVE-enumeration
280278
# section block (no content is baked at setup time).
281279
agents_md_guidance_sync_homeboy_cli() {
282-
if command -v homeboy >/dev/null 2>&1; then
280+
local homeboy_path
281+
homeboy_path="$(type -P homeboy 2>/dev/null || true)"
282+
if [ -n "$homeboy_path" ] && [ -f "$homeboy_path" ] && [ -x "$homeboy_path" ]; then
283283
agents_md_guidance_register_homeboy_cli
284284
else
285285
agents_md_guidance_unregister_homeboy_cli
@@ -288,14 +288,9 @@ agents_md_guidance_sync_homeboy_cli() {
288288

289289
# agents_md_guidance_register_homeboy_cli
290290
#
291-
# Writes a self-contained PHP block whose SectionRegistry callback shells
292-
# out to `homeboy --help` at compose time and parses the Commands: block in
293-
# PHP. The block is marker-delimited (BEGIN/END agents-md-guidance:homeboy-cli)
291+
# Writes a self-contained PHP block whose SectionRegistry callback verifies the
292+
# Homeboy binary remains available at compose time. The block is marker-delimited
294293
# so it is idempotent and removable by the standard unregister path.
295-
#
296-
# No homeboy output is captured at setup time — that was the #254 bug. The
297-
# callback is the only thing that touches homeboy, and it runs on every
298-
# `wp datamachine memory compose AGENTS.md`.
299294
agents_md_guidance_register_homeboy_cli() {
300295
local file
301296
file="$(agents_md_guidance_mu_plugin_path)" || {
@@ -313,12 +308,6 @@ agents_md_guidance_register_homeboy_cli() {
313308

314309
agents_md_guidance_ensure_mu_plugin_file || return 1
315310

316-
local new_block
317-
new_block="$(_agents_md_guidance_render_homeboy_live_block)" || {
318-
warn " agents_md_guidance_register_homeboy_cli: could not render live block — skipping"
319-
return 1
320-
}
321-
322311
if [ "${DRY_RUN:-false}" = true ]; then
323312
echo -e "${BLUE}[dry-run]${NC} Would register live AGENTS.md guidance section 'homeboy-cli' in $file"
324313
echo -e "${BLUE}[dry-run]${NC} Block:"
@@ -354,25 +343,9 @@ agents_md_guidance_unregister_homeboy_cli() {
354343
# _agents_md_guidance_render_homeboy_live_block
355344
#
356345
# Emits the PHP for the homeboy-cli section block. The block is
357-
# self-contained: it defines two helper functions (guarded by
358-
# `function_exists` so re-firing the datamachine_sections action does not
359-
# fatally redeclare them) and then registers a SectionRegistry section
360-
# whose callback invokes the live enumerator.
361-
#
362-
# The helpers:
363-
# wp_coding_agents_render_homeboy_cli_section()
364-
# Top-level orchestrator. Resolves `homeboy` on PATH, reads
365-
# `--version` and the binary mtime for the cache key, checks the WP
366-
# transient cache, shells out to `homeboy --help`, hands the help
367-
# text to the parser, caches the rendered markdown, and returns it.
368-
# Returns '' (section contributes nothing) when homeboy is absent,
369-
# shell_exec is unavailable, the binary fails, or the help text has
370-
# no parseable Commands: block.
371-
# wp_coding_agents_parse_homeboy_cli_help( $help )
372-
# Pure parser. Faithful PHP port of the original python parser:
373-
# recognizes the `Commands:` block, ends at blank line / Options:,
374-
# drops the `help`/`list` meta commands, renders the same markdown
375-
# shape (intro, optional "Common entrypoints", full list, footer).
346+
# self-contained: it defines one helper (guarded by `function_exists` so
347+
# re-firing the datamachine_sections action does not fatally redeclare it) and
348+
# registers a SectionRegistry section whose callback checks live presence.
376349
#
377350
# Quoted heredoc ('PHP_BLOCK') so PHP $variables, backticks, and ${...}
378351
# are emitted verbatim — bash never touches them.
@@ -402,161 +375,41 @@ _agents_md_guidance_render_homeboy_live_block() {
402375
return '';
403376
}
404377
405-
// shell_exec is the safe argv form here (hard-coded `homeboy`
406-
// subcommands, no user input). It can be disabled in php.ini —
407-
// in that case we degrade to a no-op rather than emit a broken
408-
// section.
409-
if ( ! is_callable( 'shell_exec' ) ) {
410-
return '';
411-
}
378+
return <<<'MD'
379+
## Homeboy
412380
413-
// Cache key on the Homeboy identity and this installed renderer.
414-
// Homeboy upgrades change the binary signals; wp-coding-agents
415-
// upgrades change the generated MU-plugin hash. Either change
416-
// must re-render the complete section because the cached value
417-
// includes both command output and static guidance prose.
418-
$version_out = @shell_exec( escapeshellarg( $homeboy ) . ' --version 2>/dev/null' );
419-
$version = ( is_string( $version_out ) ) ? trim( $version_out ) : '';
420-
$mtime = @filemtime( $homeboy );
421-
$renderer_rev = @md5_file( __FILE__ );
422-
$cache_key = 'wca_homeboy_cli_agents_md_' . md5( $homeboy . '|' . $version . '|' . ( $mtime ?: '0' ) . '|' . ( $renderer_rev ?: 'unknown' ) );
423-
424-
if ( is_callable( 'get_transient' ) ) {
425-
$cached = get_transient( $cache_key );
426-
if ( is_string( $cached ) && $cached !== '' ) {
427-
return $cached;
428-
}
429-
}
381+
Homeboy orchestrates coding agents, deterministic gates, evidence, promotion, review, releases, and deployments. Data Machine Code owns authoritative repository and worktree state; Homeboy consumes managed worktrees to execute and finalize work.
430382
431-
$help = @shell_exec( escapeshellarg( $homeboy ) . ' --help 2>/dev/null' );
432-
if ( ! is_string( $help ) || $help === '' ) {
433-
return '';
434-
}
435-
436-
$content = wp_coding_agents_parse_homeboy_cli_help( $help );
437-
if ( $content === '' ) {
438-
return '';
439-
}
440-
441-
if ( is_callable( 'set_transient' ) ) {
442-
set_transient( $cache_key, $content, 3600 );
443-
}
444-
445-
return $content;
446-
}
447-
}
448-
449-
if ( ! function_exists( 'wp_coding_agents_parse_homeboy_cli_help' ) ) {
450-
function wp_coding_agents_parse_homeboy_cli_help( $help ) {
451-
// Faithful PHP port of the original python parser. See
452-
// lib/agents-md-guidance.sh history.
453-
$commands = array();
454-
$in_commands = false;
455-
foreach ( preg_split( '/\r\n|\r|\n/', (string) $help ) as $raw ) {
456-
$stripped = trim( $raw );
457-
if ( ! $in_commands ) {
458-
if ( $stripped === 'Commands:' ) {
459-
$in_commands = true;
460-
}
461-
continue;
462-
}
463-
464-
// The commands block ends at the first blank line or the
465-
// Options: header.
466-
if ( $stripped === '' || $stripped === 'Options:' || strpos( $raw, 'Options:' ) === 0 ) {
467-
break;
468-
}
469-
470-
if ( ! preg_match( '/^\s+([A-Za-z0-9][A-Za-z0-9_-]*)\s{2,}(.+?)\s*$/', $raw, $matches ) ) {
471-
// Continuation / wrapped summary lines have no command
472-
// token; ignore them.
473-
continue;
474-
}
475-
476-
$commands[] = array( $matches[1], trim( $matches[2] ) );
477-
}
478-
479-
if ( ! $commands ) {
480-
return '';
481-
}
482-
483-
// `help` / `list` are meta commands; drop them from the map.
484-
// The footer already tells the agent how to discover
485-
// everything.
486-
$skip = array( 'help' => true, 'list' => true );
487-
$commands = array_values(
488-
array_filter(
489-
$commands,
490-
static function ( $c ) use ( $skip ) {
491-
return ! isset( $skip[ $c[0] ] );
492-
}
493-
)
494-
);
495-
496-
if ( ! $commands ) {
497-
return '';
498-
}
499-
500-
$summaries = array();
501-
foreach ( $commands as $c ) {
502-
$summaries[ $c[0] ] = $c[1];
503-
}
504-
505-
$common_order = array(
506-
'status',
507-
'triage',
508-
'worktree',
509-
'review',
510-
'build',
511-
'test',
512-
'agent-task',
513-
'runs',
514-
);
515-
516-
$lines = array();
517-
$lines[] = 'Homeboy is the host orchestrator binary — build, deploy, release, triage, test, and inspect components from the CLI. The command map below is generated live from `homeboy --help` at AGENTS.md compose time, so it always reflects the currently-installed homeboy binary.';
518-
519-
$common_entrypoints = array();
520-
foreach ( $common_order as $name ) {
521-
if ( isset( $summaries[ $name ] ) ) {
522-
$common_entrypoints[] = $name;
523-
}
524-
}
525-
if ( $common_entrypoints ) {
526-
$lines[] = '';
527-
$lines[] = 'Common entrypoints:';
528-
foreach ( $common_entrypoints as $name ) {
529-
$lines[] = '- `homeboy ' . $name . '` — ' . $summaries[ $name ];
530-
}
531-
}
532-
533-
$lines[] = '';
534-
foreach ( $commands as $c ) {
535-
$lines[] = '- `homeboy ' . $c[0] . '` — ' . $c[1];
536-
}
383+
**Default routing**
384+
- One tracked change: `homeboy agent-task cook`
385+
- Multiple independent changes: `homeboy agent-task fanout cook-batch`
386+
- Review a candidate: `homeboy review`
387+
- Inspect runs and evidence: `homeboy runs`
388+
- Repeating workflows: `homeboy agent-task loop`; explicitly stateful workflows: `homeboy agent-task controller`
389+
- Component and runner health: `homeboy status` and `homeboy runner status`
537390
538-
$lines[] = '';
539-
$lines[] = 'For agent work, use `homeboy agent-task cook` for one issue or reviewable PR, `homeboy agent-task fanout cook-batch` for multiple independent issues, `homeboy agent-task loop` for a named repeating workflow, and `homeboy agent-task controller` for workflows with explicit actions, events, waits, or policy state.';
540-
$lines[] = 'Inspect live configuration with `homeboy config show`. Discover current agent-task providers with `homeboy agent-task providers`.';
541-
$lines[] = 'Discover everything: `homeboy --help`. Drill into a command with `homeboy <command> --help`, including `homeboy config --help` and `homeboy agent-task --help`. Releases (`homeboy release`) and deploys (`homeboy deploy`) are operator actions — run them only when the user explicitly asks.';
391+
**Operator boundary**
392+
Run `homeboy release` or `homeboy deploy` only when the user explicitly asks.
542393
543-
return implode( "\n", $lines );
394+
**Discovery**
395+
Use `homeboy --help` and `homeboy <command> --help` for the live command contract. Inspect active configuration with `homeboy config show` and provider readiness with `homeboy agent-task providers`.
396+
MD;
544397
}
545398
}
546399
547400
\DataMachine\Engine\AI\SectionRegistry::register(
548401
'AGENTS.md',
549402
'homeboy-cli',
550-
34,
403+
30,
551404
static function () {
552405
return wp_coding_agents_render_homeboy_cli_section();
553406
},
554407
array(
555-
'label' => 'Homeboy CLI',
556-
'description' => 'Host orchestrator command map, enumerated live from \'homeboy --help\' at AGENTS.md compose time.',
408+
'label' => 'Homeboy',
409+
'description' => 'Host orchestration routing, safety, and discovery guidance.',
557410
'owner' => 'wp-coding-agents',
558411
'freshness' => 'live',
559-
'conditions' => 'Generated live from \'homeboy --help\' at AGENTS.md compose time on hosts where the homeboy binary is installed; removed when homeboy is absent. Cached briefly via WP transient keyed on the homeboy binary mtime and version, so a `homeboy upgrade` converges on the next compose without a wp-coding-agents sync.',
412+
'conditions' => 'Registered on hosts where the homeboy binary is installed and omitted at compose time when the binary is unavailable.',
560413
)
561414
);
562415
// END agents-md-guidance:homeboy-cli

tests/agents-md-guidance.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,14 +304,15 @@ namespace {
304304
'abilities_static' => ( \$abilities[4]['freshness'] ?? null ) === 'static',
305305
'source_has_core' => str_contains( \$source_content, '\`wp-includes/\`' ),
306306
'source_has_code' => str_contains( \$source_content, '\`wp-content/plugins/\`' ) && str_contains( \$source_content, '\`wp-content/themes/\`' ),
307-
'source_has_original_intro' => str_contains( \$source_content, 'grep and read them to understand code, but never edit them directly' ),
307+
'source_promotes_direct_reference' => str_contains( \$source_content, 'verify core APIs, hooks, conventions, and runtime behavior instead of relying on assumptions' ),
308+
'source_keeps_installed_tree_read_only' => str_contains( \$source_content, 'Make code changes in the configured managed workspace' ),
308309
'abilities_has_tools' => str_contains( \$abilities_content, 'active runtime tool listings' ),
309310
]);
310311
}
311312
PHP
312313

313314
RESULT=$(php "$MIXED_SHIM")
314-
EXPECTED='{"source_priority":1,"abilities_priority":2,"source_owner":"wp-coding-agents","abilities_owner":"wp-coding-agents","source_static":true,"abilities_static":true,"source_has_core":true,"source_has_code":true,"source_has_original_intro":true,"abilities_has_tools":true}'
315+
EXPECTED='{"source_priority":1,"abilities_priority":2,"source_owner":"wp-coding-agents","abilities_owner":"wp-coding-agents","source_static":true,"abilities_static":true,"source_has_core":true,"source_has_code":true,"source_promotes_direct_reference":true,"source_keeps_installed_tree_read_only":true,"abilities_has_tools":true}'
315316
assert_eq "$RESULT" "$EXPECTED" "wp-coding-agents owns ordered guidance after mixed-version registration"
316317

317318
echo

0 commit comments

Comments
 (0)