library: an agent that can't be given instructions, skills or MCP servers says where they go instead and lists the agents here that take them: OpenChamber has OpenCode's (give them to opencode), Claude Desktop keeps its instructions in its own settings and its Code tab reads Claude Code's (MOMO on Discord)
OpenChamber's server reads the global AGENTS.md, skills folder and opencode.json from OpenCode's config folder (openchamber/openchamber packages/web/server/lib/opencode/shared.js at 866dffd), so no path of its own is added; a second target on the same files would write them twice. Verified: TestTakesSaysWhereInstead fails on the old Takes with "Claude Desktop has no user-wide place for instructions that magpie knows of"; internal/library passes in a sandbox HOME.
This commit is contained in:
1 parent
7712ef8e7c
commit
c28a819a8e
3 files changed
+52
-1
No files matched your search
@@ -38,6 +38,7 @@ agents RTK, a CLI that cuts shell output down before the model reads it.
|
||||
- A server an agent can't reach is not written there, and `mcpFile.supports` says why. For example, Claude Desktop takes no remote server, and Codex, Goose, dsh, Grok and Command Code take no SSE.
|
||||
- A server's headers (remote) or environment (command) can name a variable as `${NAME}` (#1250). `library.json` keeps the placeholder, and `refsOf` gives each MCP format the agent's own syntax, with the agent's source cited beside it: `${NAME}` for most, `{env:NAME}` for OpenCode and MiMo, `${env:NAME}` for Cursor, and Codex's own keys (`bearer_token_env_var`, `env_http_headers`, `env_vars`). Goose gets `${NAME}` plus `env_keys`. An agent with no syntax (Claude Desktop, Antigravity, Kimi, Cline, ZCode, dsh, Devin, Pi with pi-mcp-extension) is never written the value: `refsProblem` makes `supports` refuse the server, a magpie entry already there is taken out, and `AgentView.NoEnvRefs` greys its chip with the reason. Codex and Goose's extra keys are magpie's only while the server names a variable there (`refKeys`), so the user's own `env_vars` or `env_keys` are kept. `CheckServers` expands the variable from magpie's own environment, and one that isn't set is `novar`, naming it.
|
||||
- WorkBuddy's servers go in `$WORKBUDDY_CONFIG_DIR/mcp.json` (default `~/.workbuddy`), and CodeBuddy Code's go in the first of `.mcp.json`, `mcp.json` and `~/.codebuddy.json` that exists, as `resolveMcpFilePath` reads them (#1266). WorkBuddy connects a server only after the user has switched it on once in its own MCP settings. It keeps that approval in `mcp-approvals.json`, keyed by the command, args and env names or the URL's origin, so changing those asks again. magpie never writes the approval, and the servers page says so when a server is given to WorkBuddy.
|
||||
- An agent with no place for an item is refused by `Takes`, never recorded as given it. The refusal lists the agents here that take that item (`takenBy`), and says where it goes instead (`noPlace`): OpenChamber reads OpenCode's global AGENTS.md, skills folder and opencode.json (its server's `shared.js`), so it gets them from OpenCode; Claude Desktop's chat keeps its instructions in its own settings, with the Claude account, and its Code tab reads Claude Code's.
|
||||
- Removing RTK never uses `rtk init --uninstall`. That command deletes Gemini's `GEMINI.md` whole and removes Claude Code, OpenCode and Cursor together.
|
||||
- CC Switch's own skills folder is only ever read.
|
||||
- Skills installed together (`InstallSkills`, `InstallMarketSkill`, `AddNewSkills`, through `installFrom` and `installChange`) install each on its own. One the library lists from the same source, or a folder in the library's own skills folder holding exactly that skill's files (left by an install that stopped before the library was saved), is had already and goes in `Result.Had`. Its files are never written, so the user's edits stay. Another skill by that name, listed or only in the folder, or a folder that can't be read, is left as it is and goes in `Result.Skipped` with why. The rest are installed and named in `Result.Installed`. Only when nothing was installed or had does the change fail, with the first reason.
|
||||
|
||||
@@ -147,6 +147,23 @@ func TestTakesRefusesAlma(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Claude Desktop keeps its instructions in its own settings and OpenChamber
|
||||
// reads OpenCode's: the refusal says where they go instead, and lists the
|
||||
// agents here that take that kind (MOMO on Discord: "has no user-wide
|
||||
// place" said neither).
|
||||
func TestTakesSaysWhereInstead(t *testing.T) {
|
||||
sandbox(t)
|
||||
_, err := Takes("claude-desktop", "instructions")
|
||||
if err == nil || !strings.Contains(err.Error(), "give them to claude") || !strings.Contains(err.Error(), "agents here that take instructions: ") || !strings.Contains(err.Error(), "gemini") {
|
||||
t.Errorf("claude-desktop instructions: %v", err)
|
||||
}
|
||||
for _, kind := range []string{"instructions", "mcp", "skills"} {
|
||||
if _, err := Takes("openchamber", kind); err == nil || !strings.Contains(err.Error(), "give them to opencode") {
|
||||
t.Errorf("openchamber %s: %v", kind, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Every format writes a server so that reading it back gives it again, and
|
||||
// taking it out leaves the file as the user had it.
|
||||
func TestServerEveryFormat(t *testing.T) {
|
||||
|
||||
@@ -519,7 +519,40 @@ func Takes(q, kind string) (string, error) {
|
||||
}
|
||||
}
|
||||
if !has {
|
||||
return "", fmt.Errorf("%s has no user-wide place for %s that magpie knows of", a.Name, what)
|
||||
return "", fmt.Errorf("%s%s", noPlace(a, kind, what), takenBy(kind, what))
|
||||
}
|
||||
return a.ID, nil
|
||||
}
|
||||
|
||||
// noPlace says why an agent can't be given kind, and where it gets it
|
||||
// instead when another agent's files are what it reads (MOMO on Discord).
|
||||
func noPlace(a *agent.Agent, kind, what string) string {
|
||||
switch {
|
||||
case a.ID == "openchamber":
|
||||
// OpenChamber's server reads the global AGENTS.md, skills folder
|
||||
// and opencode.json from OpenCode's config folder
|
||||
// (packages/web/server/lib/opencode/shared.js), and the OpenCode it
|
||||
// runs reads them there too
|
||||
return fmt.Sprintf("OpenChamber has no place of its own for %s: it runs OpenCode on OpenCode's config, so it has what OpenCode is given · give them to opencode", what)
|
||||
case a.ID == "claude-desktop" && kind == "instructions":
|
||||
// Desktop's chat takes its instructions in its own settings, kept
|
||||
// with the Claude account, not in a file; its Code tab is Claude
|
||||
// Code, which reads Claude Code's CLAUDE.md
|
||||
return "Claude Desktop keeps its instructions in its own settings, with your Claude account, not in a file magpie can write; its Code tab runs Claude Code, which reads Claude Code's · give them to claude"
|
||||
}
|
||||
return fmt.Sprintf("%s has no user-wide place for %s that magpie knows of", a.Name, what)
|
||||
}
|
||||
|
||||
// takenBy lists the agents here that kind can be given to.
|
||||
func takenBy(kind, what string) string {
|
||||
var ids []string
|
||||
for _, t := range Targets() {
|
||||
if kind == "instructions" && t.Instructions != "" || kind == "mcp" && t.MCP != nil || kind == "skills" && t.Skills != "" {
|
||||
ids = append(ids, t.Agent.ID)
|
||||
}
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
return ""
|
||||
}
|
||||
return "\n agents here that take " + what + ": " + strings.Join(ids, ", ")
|
||||
}
|
||||
Reference in new issue
Block a user