Feature/project workspace#355
Open
perasperaactual wants to merge 7 commits into
Open
Conversation
…ppy.json config MCP servers now auto-enable on startup when config.enabled=True (the default). Previously _enabled was hardcoded False, requiring an explicit /mcp start before tools were available. load_local_mcp_config() walks up from CWD to find a project-local .code-puppy.json. sync_from_local_config() registers those servers after global config (local wins on collision, never persists to mcp_registry.json). Supports mcpServers array + mcp_servers object formats.
…eValidator LLMs sometimes pass the questions array as a JSON string. pydantic_ai rejects 'expected list, received str'. BeforeValidator(_coerce_questions_json_string) json.loads() when input is a string, passes through otherwise. Transparent to JSON Schema generation.
Add unified workspace discovery that walks up from CWD to git root looking for a .code-puppy/ directory. Reads config.json for settings including the projectOnly flag (default: false). - ProjectWorkspace frozen dataclass with root_path, workspace_path, project_only, and config fields - get_project_workspace() with per-process caching, CWD invalidation - is_project_only() convenience wrapper - get_project_agents_directory() now prefers workspace agents/ dir with backward compat for legacy .code_puppy/agents/ in CWD - PROJECT_WORKSPACE_DIR_NAME constant for easy naming changes - 22 tests covering discovery, git-root boundary, caching, config parsing, legacy fallback, and nearest-wins semantics Part 1 of 5 for project workspace support. Bead: code_puppy-9id
load_local_mcp_config() now checks the workspace first: 1. .code-puppy/mcp_servers.json (dedicated file in workspace) 2. mcpServers/mcp_servers keys in .code-puppy/config.json 3. Legacy .code-puppy.json walk-up (backward compat) MCPManager.sync_from_config() skips global ~/.code_puppy/mcp_servers.json entirely when projectOnly mode is active. Extract _parse_mcp_data() helper to DRY the format-parsing logic between workspace and legacy loading paths. 8 new tests covering workspace MCP loading, priority, variable expansion, legacy fallback, and projectOnly blocking of global config. Part 2 of 5 for project workspace support. Bead: code_puppy-9id
discover_json_agents() skips user-level agents (~/.code_puppy/agents/) when projectOnly is active — only workspace JSON agents are loaded. _discover_agents() in projectOnly mode: - Skips all builtin Python agents (security-auditor, qa-kitten, etc.) - Registers only the base code-puppy agent as fallback - Skips plugin-registered agents (section 3) - JSON agents still load (via discover_json_agents which gates internally) This is the core isolation mechanism: in projectOnly mode, list_agents() returns only what the workspace defines plus the base code-puppy agent. 6 new tests covering user-agent skip, additive mode, name collision, base agent always available, builtin agent hiding, and normal mode. Part 3 of 5 for project workspace support. Bead: code_puppy-9id
Add _load_project_plugins() for loading plugins from workspace .code-puppy/plugins/ directory, same mechanism as user plugins. load_plugin_callbacks() now: - Always loads builtin plugins (code-puppy internals) - Skips user plugins (~/.code_puppy/plugins/) in projectOnly mode - Loads project plugins from workspace when available - Returns 3-key dict: builtin, user, project 6 new tests covering project plugin discovery, user plugin skip in projectOnly, user plugin inclusion without projectOnly, builtin always loading, result structure, and no-workspace fallback. Part 4 of 5 for project workspace support. Bead: code_puppy-9id
PROJECT_WORKSPACE_DIR_NAME = ".code_puppy" (underscore) — consistent with upstream's .code_puppy/ convention (see 1298654), the existing AGENTS_DIR path, and the general code_puppy naming style. Legacy .code-puppy.json flat file is unchanged — that's a separate pre-existing convention for the walk-up MCP config file. Update test_workspace_preferred_over_legacy to mock get_project_workspace() directly, since workspace and legacy paths now share the same directory name and can no longer be distinguished by filesystem layout alone. Bead: code_puppy-9id # Conflicts: # CHANGES_FROM_UPSTREAM.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds a unified project-local workspace directory (.code-puppy/) that lets projects define their own MCP servers, JSON agents, and plugins without touching the global ~/.code_puppy/ config. An optional projectOnly flag switches from additive merge to full isolation.
This is the .vscode/ pattern applied to code-puppy; reproducible project-scoped AI agent environments that work out of the box with no manual global config surgery.
Walk-up discovery: on startup, code-puppy walks from CWD to the git root looking for .code-puppy/. The first directory found is the project workspace. Config never crosses a git root boundary.
my-project/
└── .code-puppy/
├── config.json # { "projectOnly": false } ← optional
├── mcp_servers.json # project MCP servers
├── agents/ # JSON agent definitions
└── plugins/ # project-scoped plugins
config.json supports one flag: projectOnly (boolean, default false).
projectOnly: false (default) — additive merge, local wins on name collision. Zero behavior change for users without a .code-puppy/ directory.
projectOnly: true — global ~/.code_puppy/ is skipped entirely:
┌────────────────────────────────────────────────────────┬─────────────────┐
│ Resource │ Effect │
├────────────────────────────────────────────────────────┼─────────────────┤
│ Global mcp_servers.json │ Skipped │
│ ~/.code_puppy/agents/ user JSON agents │ Skipped │
│ Builtin Python agents (security-auditor, qa-kitten, │ Hidden │
│ etc.) │ │
│ ~/.code_puppy/plugins/ user plugins │ Skipped │
│ .code-puppy/ workspace agents/plugins │ Loaded │
│ Builtin code-puppy plugins │ Always loaded │
│ Base code-puppy agent │ Always │
│ │ available │
└────────────────────────────────────────────────────────┴─────────────────┘