Trae (trae)
Output
AGENTS.md # canonical entry-point pointer body (written by sync, shared path)
.trae/rules/<name>.md # one per rule
.trae/agents/<name>.md # one per agent (project subagent)
.trae/skills/<name>/SKILL.md # one folder per skill
.trae/commands/<name>.md # one per command
.trae/hooks.json # when hook entries exist
.trae/.ignore # when ignore entries exist
.trae/mcp.json # MCP server registry
ByteDance Trae reads persistent rules from .trae/rules/ and the root AGENTS.md natively, and project subagents from .trae/agents/.
Rules: every
.trae/rules/*.mdfile carriesdescription/globs/alwaysApplyYAML frontmatter, the same three-field activation matrix Cursor's.mdcrules use.alwaysApplydefaults totrue. Atruerule omitsglobsentirely.alwaysApply: falsewith no explicitglobsfalls back to the Claude spelling (paths, comma-joined).- The Trae docs document all three keys but not what a file carrying none of them defaults to, so this adapter always emits them rather than leave the activation mode to guesswork (#607).
- Set
x-trae.scene: git_messageon a rule to mark it for AI-generated Git commit messages. The vendor states the field "is compatible with existing fields such as alwaysApply, description, and globs", so it merges onto the same block instead of gating behind it (#635).
Agents: one project subagent per agent at
.trae/agents/<name>.md, the path Trae's subagents doc tables as{project_folder}/.trae/agents/{my_agent}.md.- Frontmatter carries
nameanddescription(both required), plus optionalmodel,tools,disallowedTools, andmcpServers. The body after the closing delimiter is the system prompt. - Agents used to flatten into
.trae/rules/agent-<name>.md, which reached the rules loader instead of the subagent loader and dropped every field rule frontmatter has no key for (target-audit 2026-08-27, #638). A managed copy at the old name is swept for every current agent. toolspasses through with no translation table: Trae's vocabulary is Claude-style and covers agnostic-ai's set exactly (Bash,Edit,Glob,Grep,Read,Write,WebFetch,WebSearch, plusSkill,LSP,TodoWrite, andmcp__<server>__<tool>). It is comma-joined into the string spelling the vendor documents rather than a YAML list.modelis the opposite case: Trae accepts "Only built-in models provided by TraeCode", a table of its own IDs (gpt-5.4,minimax-m3, ...) with no overlap with a cross-targetmodel:value, so a bare generic model drops with a coverage note. Name one for Trae withmodel: {trae: <id>}orx-trae.model.disallowedToolsandmcpServersreach the file throughx-traethe same way.x-trae.disallowedToolsis a denylist that wins overtoolsand is comma-joined like it.- Subagents sit behind a switch: "Go to Settings > Beta > Subagents, ensure that the Enable Subagents Directory switch is toggled on." The vendor never states its default, so a project may need that switch flipped before the emitted files load.
- Frontmatter carries
Skills: one folder per skill under
.trae/skills/<name>/SKILL.md, Trae's native skills layout. The SKILL.md frontmatter carriesname+description. Sibling assets (examples/,templates/,resources/) copy byte-for-byte alongside it. A flat file directly under.trae/rules/never loads as a skill, so this is a folder, not a rule-form file.Commands: one
.mdper command under.trae/commands/<name>.md,name+descriptionfrontmatter and the body as the prompt.- This shape is vendor-confirmed rather than reverse-engineered: Trae's slash-commands doc tables the same two frontmatter fields,
NameandDescription, matching what this adapter already emitted from real.trae/commands/*.mdfiles. Onlynameanddescriptionare documented, so nothing else emits. - Nesting under
.trae/commands/is bounded at 3 levels, not merely organizational: the vendor's own example tree marks a file 3 levels deep as the deepest readable one and a file 4 levels deep as exceeding the limit, so this adapter still writes every command flat rather than risk crossing it.
- This shape is vendor-confirmed rather than reverse-engineered: Trae's slash-commands doc tables the same two frontmatter fields,
MCP servers: merge into
.trae/mcp.jsonunder a rootmcpServersmap, confirmed by a direct fetch of Trae's own MCP doc.- Stdio entries carry
command(required) plus optionalargs/env. HTTP entries carryurl(required) plus optionalheaders. Neither carries atypefield: Trae tells the two apart by which ofcommandorurlis present, so this adapter never writes one. disabledhas no documented per-server key either (only a project-level MCP toggle under Settings > MCP), so a spec'sdisabled: trueis stripped with a coverage note instead of written dead.- The vendor doc cautions that a stdio
commandmust not contain spaces, or parsing fails.
- Stdio entries carry
Hooks: written to
.trae/hooks.json, the project tier of Trae's hook configuration reference: "Project Hook |$PROJECT_FOLDER/.trae/hooks.json| Applies only to the current project or workspace" (target-audit 2026-09-11, #729).- The file is an integer
versionenvelope ("The default value is 1, and currently only 1 is supported") around ahooksmap keyed by event, each event holding the same{matcher, hooks: [{type, command, timeout}]}groups Claude Code, Codex, OpenHands, and Qoder already get, so one hook spec feeds all five. - Trae documents six events (
SessionStart,UserPromptSubmit,PreToolUse,PostToolUse,Stop,Notification) and three fields per entry:type("currently onlycommandis supported"),command, andtimeout(seconds, default 30). - A spec's
loop_limitalso emits, Trae's own group-level field capping how often aStophook may block the agent from stopping. Leave it unset for the vendor default of 5. - The matcher vocabulary is the trap here. Trae's hook
tool_nametable is not its subagenttoolstable: it readsRead,Write,Edit,Glob,Grep,LS,RunCommand,WebSearch,WebFetch,AskUserQuestion,Skill, andmcp__<serverName>__<toolName>. The terminal tool isRunCommand, notBash, and there is noTodoWrite, so a Claude-stylematcher: Bashparses as a valid regex and then matches nothing. That case emits verbatim with a coverage note rather than a guessed rename, the same line OpenHands and Crush hold. matcheris read onPreToolUse,PostToolUse, andNotificationonly. OnNotificationit selects a notification type (idle_prompt,permission_prompt, ...) rather than a tool.- Project hooks are enabled through Settings > Hooks behind a security-consent panel ("read the warning message. After confirming there is no risk, click the Enable button"), the same shape as the project-level MCP toggle this adapter already emits past, so the file is inert until a user flips it.
Trae also reads Claude Code's hook file: "Additionally, TraeCode supports reading hook configurations from Claude Code", with
$PROJECT_FOLDER/.claude/settings.jsonand.claude/settings.local.jsonin its own Project Hook table, and "If both Claude Code hooks and TraeCode hooks are enabled at the same time, TraeCode will read all enabled hook configurations and execute them in combination."A repo syncing
claudeandtraetogether therefore runs every hook twice, but only after you turn it on: automate-actions-with-hooks says "Toggle the Import Hook configuration in CLAUDE switch on", and it is off by default, behind the same security-warning panel (#756).- The file is an integer
Ignore: ignore specs emit as
.trae/.ignore, the path Trae's own Settings > Indexing & Docs flow creates: "TraeCode automatically creates the.ignorefile in the.trae/folder and opens this file in the editor" (docs.trae.ai/ide/ignore-files, target-audit 2026-09-11, #728).- The filename is a bare
.ignore, scoped by the directory rather than a tool prefix. It supplements.gitignore, which Trae already honors by default, and governs codebase indexing plus#Workspace/#Foldercontext ("any ignored files or folders will not be included as context"). - Unlike every other ignore target, it does not apply on save: "The
.ignorefile will take effect after re-indexing is complete", so a freshly synced pattern needs a Build under Settings > Indexing & Docs before it holds. - Multiple specs concatenate. Override via
outputs.trae.ignore-file.
- The filename is a bare
Config keys
| Key | Default |
|---|---|
outputs.trae.rules-dir | .trae/rules |
outputs.trae.agents-dir | .trae/agents |
outputs.trae.skills-dir | .trae/skills |
outputs.trae.commands-dir | .trae/commands |
outputs.trae.hooks-file | .trae/hooks.json |
outputs.trae.ignore-file | .trae/.ignore |
outputs.trae.mcp-file | .trae/mcp.json |
Verify
- Install Trae from trae.ai.
- Check the tree:
ls AGENTS.md .trae/rules/ .trae/agents/ .trae/skills/ .trae/commands/ .trae/mcp.json .trae/hooks.json .trae/.ignoregrep "Generated by agnostic-ai" .trae/rules/*.mdpython -m json.tool .trae/mcp.json > /dev/nullpython -m json.tool .trae/hooks.json > /dev/null
- Open the project:
- The Rules panel lists every
.trae/rules/*.mdwith no parse warnings. - Each
.trae/skills/<name>/loads as a skill. - Each
.trae/commands/<name>.mdis invokable from chat. - Settings > MCP lists each
.trae/mcp.jsonserver (project-level MCP toggled on).
- The Rules panel lists every
- Turn on Settings > Beta > Subagents > Enable Subagents Directory, then ask the Agent to delegate to one by name; each
.trae/agents/<name>.mdis routable and the frontmatter parses with no BOM or delimiter error. - Enable the project hook under Settings > Hooks (accept the security panel). Configured Hooks lists the file, and triggering the matched tool runs the command.
- Edit
.trae/.ignore, then Build under Settings > Indexing & Docs. The ignored paths drop out of#Workspacecontext.