Skip to content

Skip plugin hook and vendor dirs when loading local agents - #1553

Open
yablokolabs wants to merge 2 commits into
CodebuffAI:mainfrom
yablokolabs:fix/skip-vendor-agent-scan
Open

yablokolabs wants to merge 2 commits into
CodebuffAI:mainfrom
yablokolabs:fix/skip-vendor-agent-scan

Conversation

@yablokolabs

Copy link
Copy Markdown

Summary

  • loadLocalAgents/listLocalAgentFiles now skip hooks/ and vendor/ directories under .agents, so plugin support scripts are not imported as agent definitions.
  • Fixes a startup failure where ponytail's hooks/ponytail-subagent.js ran on import and called process.exit(0), exiting Freebuff before the TUI.
  • Updated the loader docs and changelog; added regression coverage for both layouts.

Why

A third-party plugin installed at ~/.agents/vendor/ponytail contains hooks/ponytail-subagent.js, which is executable support code, not an agent. The recursive loader imported it, ran its top-level code, and the hook's process.exit(0) killed the CLI with status 0. The CLI trust inventory uses the same file list, so skipping these support directories keeps the trust prompt consistent.

Refs #1009 (closed duplicate; this is the underlying bug).

Test Plan

  • cd sdk && bun test src/__tests__/load-agents.test.ts — 39 pass, 0 fail
  • cd sdk && bun run test — 1039 pass, 43 skip, 0 fail
  • Manual: real ponytail plugin under .agents/vendor loads 0 agents and does not exit

Notes

cd sdk && bun run typecheck is currently red on untouched AI SDK providerOptions errors (common/src/util/messages.ts, packages/agent-runtime, sdk/src/impl/llm.ts); the changed files are not in the error list.

loadLocalAgents imports every executable file under .agents as an agent. A
plugin installed under .agents/vendor has hook scripts such as
hooks/ponytail-subagent.js; importing that hook runs its top-level code, and
ponytail calls process.exit(0), so the CLI exits before the TUI.

Skip hooks/ and vendor/ directories in listLocalAgentFiles, which also keeps
the CLI trust gate consistent. Add regression coverage for both layouts and
update the loader docs/changelog.
@yablokolabs

Copy link
Copy Markdown
Author

Verification on c836ff5:

cd sdk && bun test src/__tests__/load-agents.test.ts

39 pass
0 fail

cd sdk && bun run test

1039 pass
43 skip
0 fail

Manual loader check against the real ponytail plugin installed under .agents/vendor:

loaded agents: 0

The hook was not imported and the process did not exit.

@codebuff-team

Copy link
Copy Markdown
Contributor

Good find and a clean fix. shouldSkipAgentDirectory in sdk/src/agents/load-agents.ts already excluded skills/, scripts/, node_modules and dot-dirs from the recursive agent import; adding hooks and vendor to that list is a natural, low-risk extension rather than a new mechanism, which keeps the change small and easy to port.

The regression tests are solid - both the listLocalAgentFiles snapshot test and the new skips plugin hook directories test exercise the exact failure mode (a top-level process.exit(0) in an imported file), and they check that a real sibling agent still loads. The docs and changelog updates in docs/agents-and-tools.md and sdk/CHANGELOG.md correctly describe the new skip set and its effect on the trust-gate inventory in agent-dir-trust.ts, which is important since that file reuses listLocalAgentFiles.

One thing worth flagging for the maintainers porting this: hardcoding hooks and vendor as reserved names is a heuristic, not a real namespacing mechanism, so a user who legitimately names a directory vendor for their own agents (not a plugin) would silently lose those agents with no error. That's an existing pattern already accepted for skills/scripts, so it's consistent, but it's worth a one-line note in the docs about the collision risk, or a .agentsignore-style escape hatch in a follow-up. Not a blocker as-is.

Overall this is a focused, well-tested fix for a real startup-crash bug with a clear root cause - good first PR.

@codebuff-team codebuff-team added bot:triaged Classified by the community triage bot pr:port-candidate Worth porting into the private source tree labels Oct 25, 2026
…names

A directory named vendor holding the user's own agents is now skipped, with no
message. Naming that in the loader docs is cheaper than an ignore file and
stops the silent loss from reading as a bug.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@yablokolabs

Copy link
Copy Markdown
Author

Added the collision note as 9c480ab. docs/agents-and-tools.md now names vendor/ and hooks/ as reserved, says the skip is silent, and tells the user to put their own agents in another directory. An .agentsignore would serve a user who genuinely needs those names better, so I left that as the follow-up rather than growing this PR.

I checked the rest of the port at c836ff5 as well:

  • listLocalAgentFiles reuses shouldSkipAgentDirectory, so the trust inventory in cli/src/utils/agent-dir-trust.ts cannot disagree with what loadLocalAgents imports.
  • Re-ran cd sdk && bun test src/__tests__/load-agents.test.ts: 39 pass, 0 fail.
  • The repo's bundled agents/ tree has no vendor/ or hooks/ directory, so no shipped agent changes behavior.

No other changes to the skip list.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:triaged Classified by the community triage bot pr:port-candidate Worth porting into the private source tree

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants