Qoder (qoder)
Output
AGENTS.md # canonical entry-point pointer body (written by sync, shared path)
.qoder/rules/<name>.md # one per rule (native, one file per rule)
.qoder/agents/<name>.md # one per agent (native, one file per agent)
.qoder/skills/<name>/SKILL.md # one folder per skill, plus any bundled assets
.qoder/commands/<name>.md # one per command
.qoder/settings.json # when MCP, hook, or settings entries exist (merged; unrelated keys preserved)
Alibaba Qoder reads project rules from .qoder/rules/ natively, one Markdown file per rule, and also reads the root AGENTS.md. The per-rule files take precedence over AGENTS.md, so rules emit there rather than inlining into the shared pointer.
Skills emit into their own native folder tree at .qoder/skills/<name>/SKILL.md (docs.qoder.com/extensions/skills, target-audit 2026-08-08, #558): "Each Skill contains a SKILL.md file", at project scope .qoder/skills/{skill-name}/SKILL.md (the vendor doc also lists a user-level ~/.qoder/skills/{skill-name}/SKILL.md tier this adapter has no reach into). That doc does not list .agents/skills/ as a compatible path, unlike Kilo Code, Augment, and OpenHands, so this is Qoder's own tree rather than a dedupe target for the shared one.
import qoder reads rules, agents, skill folders, commands, and portable settings fields. It does not yet read hooks or MCP servers back out of .qoder/settings.json.
Agents: Qoder Subagents reads
.qoder/agents/<name>.md, one file per agent.nameanddescriptionare required frontmatter;model,tools,color,skills, andmcpServersare optional.color(one of eight named values:red,blue,green,yellow,purple,orange,pink,cyan) is documented on the CLI field reference rather than the smaller extensions page, which defers to the CLI page as "the complete guide" for the identical path. It is a shared portable field Augment and Kilo Code already promote the same way.toolsrenders as a comma-separated string (tools: Read, Grep, Bash), the only form the vendor doc shows, not a YAML list.import qodersplits it back into agnostic-ai's generic list form so the spec stays usable by every other target.- Qoder's built-in tool vocabulary is Claude-style (
Bash,Edit,Write,Glob,Grep,Read,WebFetch,WebSearch), which is what makes passing agnostic-ai's generictoolslist straight through safe here, unlike Kilo Code and Augment, whose own vocabularies differ and which drop the field with a coverage note instead. skillsandmcpServershave no agnostic-ai-native shape and pass through whatever the spec declares viax-qoder.- The adapter manages
name,description,model,tools,skills, andmcpServers. Any otherx-qoderkey passes through into the agent frontmatter.
Skills: Qoder Skills reads a folder per skill at
.qoder/skills/<name>/SKILL.md. Frontmatter is plainname+description, the only keys the vendor doc shows. Bundled sibling files (scripts, references, templates) copy byte-for-byte alongsideSKILL.md, the same folder-layout render every other Agent Skills target here uses.Commands: one Markdown file per command spec at
.qoder/commands/<name>.md.- docs.qoder.com/cli/commands tables
.qoder/commands/<command_name>.mdas the project-level location, "Recommended (team sharing)", and docs.qoder.com/user-guide/commands corroborates the same path for the IDE ("Project Commands", "Only effective in the current project root directory and its subdirectories"), so this is not a CLI-only surface. - The CLI page's field table documents exactly two frontmatter keys:
description(Required: Yes) andname(Required: No, "serves only as the display name in the TUI; the invocation name is always derived from the file path"). Since the filename already drives invocation, this adapter never writesnameand always writesdescription, falling back to the command's name when the spec has none. - One precedence quirk: the CLI page states that when a command with the same name exists at both the project and User levels, "the User-Level command takes precedence and overrides the project-level command with the same name", backwards from the read-order most targets document, and this adapter has no reach into the user-level tier (
~/.qoder/commands/) to warn about a same-name collision. - The IDE page describes different behavior for the same case (both entries stay listed, distinguished by "a scope indicator", rather than one overriding the other), so a project-level command this adapter writes can still be shadowed depending on which Qoder product reads it.
- docs.qoder.com/cli/commands tables
MCP: merges into
.qoder/settings.jsonunder the standardmcpServersmap (stdio:command/args/env/cwd, notype; remote:type+url/headers).- Every entry also accepts the nine fields on the vendor's "Common Optional Fields" table:
timeout(milliseconds),description,trust("Trusts the server, skipping confirmation when its tools are called"),includeTools,excludeTools,alwaysAllow,disabled("Disables the server (keeps the configuration without deleting it)"), and anoauthobject passed through as declared, since the vendor's own field list for it is open-ended. - Unrelated keys in that file (
mcp.enableAllProjectMcpServers, permissions, custom models) survive every sync; onlymcpServersis overwritten. - That holds for a JSONC file too: the vendor documents this path as "JSON format (supporting
//comments)" (docs.qoder.com/cli/settings), sosyncstrips comments and trailing commas before reading. Keys survive, comments do not, and the sync that drops them prints a one-line warning (target-audit 2026-09-11, #725).
- Every entry also accepts the nine fields on the vendor's "Common Optional Fields" table:
Settings: the shared default model maps to
.qoder/settings.jsonasmodel.name;permissions.allow,permissions.deny, andpermissions.askmap directly. The write merges with hooks, MCP servers, and unrelated native keys. Import restores those portable fields tosettings/imported.yaml.This adapter wrote the project-root
.mcp.jsonuntil #641, byte-for-byte the file Claude Code writes there, and the two deduped into one write. That only held while their emitted bytes stayed identical, and they no longer can: Qoder documents nine per-server fields Claude Code does not, Claude Code documents four Qoder does not (headersHelper,alwaysLoad, and its ownoauthandtimeoutshapes), and a spec using any of them would make two adapters write different bytes to one path.That is a hard error in the collision check, on a pair of targets both in the default set.
<project>/.qoder/settings.json → mcpServersis the vendor's other documented project-level location and Claude Code never reads it, so moving there removes the shared path instead of arbitrating it.One migration step: a
.mcp.jsonleft by an older agnostic-ai still loads, and Qoder's precedence order puts it ahead of.qoder/settings.jsonfor a same-named server. Sync cannot sweep it (a JSON file carries no provenance header, and the file may belong to Claude Code), so delete it by hand in a Qoder-only project. Seedisabledsupport by target.Hooks: merge into that same
.qoder/settings.json, under ahookskey alongsidemcpServers(docs.qoder.com/cli/hooks, "Configuration Format"):{"hooks": {"<Event>": [{"matcher": ..., "hooks": [{"type": "command", "command": ..., ...}]}]}}, the same nested shape Claude Code, Codex, and OpenHands use, so this adapter's renderer is the sharedclaudehookswire structs rather than a fourth hand-rolled copy.- 27 events, PascalCase:
SessionStart,SessionEnd,UserPromptSubmit,PreToolUse,PostToolUse,PostToolUseFailure,PermissionRequest,PermissionDenied,Stop,StopFailure,SubagentStart,SubagentStop,PreCompact,PostCompact,Notification,InstructionsLoaded,ConfigChange,CwdChanged,FileChanged,WorktreeCreate,WorktreeRemove,Elicitation,ElicitationResult,TaskCreated,TaskCompleted,TeammateIdle,Setup. That count grew from 6 at an earlier audit to 23 at #629; the authoritative list is docs.qoder.com/cli/hooks-reference, re-counted 2026-09-12, #737. - Every one of them emits, since
event:passes through verbatim, and all 27 sort in the vendor's own order ahead of any event it does not list. The last four sorted behind an unlisted event until #744, so a project already using one of those names writes different bytes after that fix. PreToolUse/PostToolUse'smatcherdocuments "Tool name (e.g.Bash,Write,Edit,Read,Glob,Grep; MCP tool names likemcp__server__tool)", Claude Code's own vocabulary, so a Claude-authored matcher reaches it unchanged, unlike OpenHands and Windsurf whose own tool names diverge.- Per entry:
command,type(alwayscommand), optionalargs,timeout(seconds, vendor default 600),statusMessage,async,asyncRewake,shell(bashorpowershell), andif(a permission-rule filter, e.g.Bash(git *)). All nine are documented with the same semanticsclaudehooks.CommandEntryalready models for Claude Code. argsswitches the entry to exec form:commandbecomes the path of a single executable and eachargselement is one literal argv entry, launched directly with no shell, so a path or argument holding a space, apostrophe,$, or backtick reaches the binary intact (#746). Qoder ignoresshellonceargsis set; a spec that sets both still writes both, andsyncprints a note saying the shell never runs.- Qoder additionally documents
env,rewakeMessage,rewakeSummary, and three more hook entry types (http,prompt,agent); none has a field on the shared hook spec, so they are unreachable from a generic spec today.
Merging
hooksandmcpServershappens in one write, not two.MergeJSONFilere-reads.qoder/settings.jsonfrom disk on every call, and two separate calls in the same sync would each see the file before the other's write landed during sync's collision-detection pass, which reads as two targets disagreeing on one file's content when only Qoder writes it.- 27 events, PascalCase:
Config keys
| Key | Default |
|---|---|
outputs.qoder.rules-dir | .qoder/rules |
outputs.qoder.agents-dir | .qoder/agents |
outputs.qoder.skills-dir | .qoder/skills |
outputs.qoder.commands-dir | .qoder/commands |
outputs.qoder.mcp-file | .qoder/settings.json (also the hooks path since the two share one file) |
Verify
- Install Qoder from qoder.com.
- Check the tree:
ls AGENTS.md .qoder/rules/ .qoder/agents/ .qoder/skills/ .qoder/commands/ .qoder/settings.jsongrep "Generated by agnostic-ai" .qoder/rules/*.md .qoder/agents/*.md .qoder/skills/*/SKILL.md .qoder/commands/*.mdfor the provenance headerpython -m json.tool .qoder/settings.json > /dev/null
- Open the project:
- The rules panel lists every
.qoder/rules/*.mdwith no parse warnings. - The agent picker lists every
.qoder/agents/*.md. - Each
.qoder/skills/<name>/folder loads as a skill. - Each
.qoder/commands/<name>.mdruns from/. - The MCP picker shows each
mcpServers.<name>from.qoder/settings.jsonconnected (project-level servers need approval on first use). - A configured hook fires on its event (e.g. a
PreToolUsehook prints or blocks before the matching tool runs).
- The rules panel lists every