[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71FSCT5DYKFCQFAY0E85QA1":3,"skill-same:01M71FSCT5DYKFCQFAY0E85QA1":79},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":51,"commitSha":52,"skillDirectory":53,"forksCount":14,"repositoryHtmlUrl":54,"repositoryHomepageUrl":6,"ownerHtmlUrl":55,"ownerBlogUrl":56,"ownerDescription":57,"updatedAt":58,"install":59,"resources":72},"01M71FSCT5DYKFCQFAY0E85QA1","operate-agent-mail",null,"ALWAYS invoke this skill when a workflow registers a mail identity, sends a message record, lists a recipient's records, reads or acknowledges one message, or waits for a later record in the agent-mail store. NEVER construct an `am` command or derive the mail project key without this skill.","outcomeeng\u002Fplugins","outcomeeng","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F257335685?v=4","01M71FRVRF36XYR3HRSCGFHK2R","Outcome Engineering","01M71FRVS4BZG17DWANFJ7EPNY",1,"MIT","https:\u002F\u002Fgithub.com\u002Foutcomeeng\u002Fplugins\u002Fblob\u002Fmain\u002Fsrc\u002Fplugins\u002Fcoding-agents\u002Fskills\u002Foperate-agent-mail\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"mail","operate agent mail","agent mail","operate","when","invoke","write","records","scripts","request","json","project","for","command","later","never","message","python3","record","store","2026-11-10 10:12:30",false,"---\nname: operate-agent-mail\ndescription: >-\n  ALWAYS invoke this skill when a workflow registers a mail identity, sends a message record, lists a recipient's records, reads or acknowledges one message, or waits for a later record in the agent-mail store. NEVER construct an `am` command or derive the mail project key without this skill.\nargument-hint: \"\u003Coperation or JSON request>\"\nallowed-tools: Write, Bash(python3 \"${CLAUDE_SKILL_DIR}\u002Fscripts\u002Fagent_mail.py\":*)\n---\n\n\u003Cobjective>\nA versioned JSON agent-mail operation result — a registered identity, a delivered record with its store-assigned id, the recipient's listed records, the message a read or an acknowledgement judged, or the first later record or a named timeout or unreachable outcome of a bounded wait — under the project key of the store the operation acted on, or that key alone as an unversioned `projectKey` answer, with every store identity preserved verbatim.\n\u003C\u002Fobjective>\n\n\u003Coperation_surface>\n\nThe source-owned request operations, each submitted as a JSON request to `run`:\n\n| Operation     | Arguments                                                   | Result data                                                               |\n| ------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------- |\n| `register`    | `agent`, `program`, `model`; optional `task`, `displayName` | the registered `agent` name and store id                                  |\n| `send`        | `record`                                                    | the `record` with its store-assigned `id`                                 |\n| `list`        | `agent`; optional `allRecords`, `includeBodies`, `limit`    | `records` listed for that recipient                                       |\n| `read`        | `agent`, `messageId`                                        | the `agent` and `messageId` the recipient judged                          |\n| `acknowledge` | `agent`, `messageId`                                        | the `agent` and `messageId` the sender can now see judged                 |\n| `wait`        | `agent`, `afterId`, `timeoutSeconds`                        | an `outcome` of `received` with the `record`, `timeout`, or `unreachable` |\n\nOne further form answers outside the request shape, so it takes no JSON request and the request-building steps of `\u003Cworkflow>` do not reach it. A `run` request naming it is rejected as `operation-unavailable`; its command is in `\u003Cinvocation_forms>`.\n\n| CLI form      | Arguments | Result data  |\n| ------------- | --------- | ------------ |\n| `project-key` | none      | `projectKey` |\n\nThe record and its delivery rules:\n\n- **Repository.** Every operation accepts an optional `repository` in its `arguments`, an absolute path string. The operation then acts on the store under the project key of that repository; a request naming none acts on the store of the adapter's own working directory. A value that is no string or no absolute path is rejected as `invalid-schema` before any command runs, and a path that resolves to no repository answers `repository-unresolved`, never the key of the adapter's own working directory. The adapter reads no overlay or configuration to select a repository; the request names it. The result's `projectKey` reports the store the operation acted on.\n- **No registration on behalf.** The adapter registers no identity for a caller: a send from a name the named store does not hold returns the store's failure as `command-failed`, and `register` against that repository creates the identity.\n- **Fields.** A `record` carries exactly `schema` (`1`), `kind`, `correlation`, `sender`, `recipient`, `subject`, `body`, and `ackRequired`; the store assigns `id` on delivery.\n- **Kinds a sender writes.** `order`, `fact`, `question`, `answer`, `delegation-request`, and the four terminal handbacks `delegation-completed`, `delegation-failed`, `delegation-rejected`, and `delegation-unavailable`. On read-back the adapter reports each record's kind as one of those or as `unclassified`, and `subject` carries the text to use in either case. Never derive a kind from a subject: the adapter owns the prefix it writes and the conditions a row meets to classify, and a row missing any of them reads as `unclassified` with its subject verbatim.\n- **Mapping.** The adapter maps `correlation` onto the store's thread, `kind` onto a subject prefix, and `ackRequired` onto the store's acknowledgement requirement, and reads each back; a store limit never shapes the record. A correlation the store's thread alphabet rejects — one with a character outside letters, digits, `.`, `_`, and `-`, a non-alphanumeric first character, or the prefix `xc-` — travels as an `xc-` escape the adapter writes and reads back to the original correlation, so any correlation round-trips. A correlation whose written thread id would exceed 128 characters is rejected as `invalid-schema` before any command runs, and so is any text argument carrying a NUL byte.\n- **Read state.** Only `read` and `acknowledge` change a record's read state. `list` and `wait` change none, so looking at records never judges them. `read` records, visibly to the recipient alone, that the recipient judged one message. `acknowledge` is a read the sender can observe. Neither stands in for the other: use `read` for a private judgment and `acknowledge` only when the sender is meant to see it.\n- **List.** `list` returns the records the recipient has not yet judged; with `allRecords` true it returns every record, read or unread. A request carrying `unreadOnly` is rejected as `invalid-schema`.\n- **One recipient.** `recipient` names one agent. A value carrying the store's `,` separator is rejected with `invalid-schema` before any command runs.\n- **Foreign rows.** A row another sender wrote reads back rather than failing the listing: without a thread it reads with `correlation: null`, classified by the kind rule above, and `ackRequired` is true for an acknowledgement status of `required`, `pending`, or `acked` and false for every other status. A thread id that is no escape the adapter writes reads back verbatim as `correlation`. A row without the store's `id`, `from`, or `subject` key is a malformed store response and fails the read as `invalid-schema`.\n- **Labels.** A position label is the display name the store records for an agent. `register` passes an optional `displayName` to the store as the agent's label and registers only the `agent` name the request supplies. A listed record, with or without a body, and a send result carry the store's `sender_display_name` verbatim in `response` beside the message, `null` when the sender has no label; a send result also carries `to_display_names`, which maps each recipient's stable name visible to the reader to its label. No label enters the `record`. A label names no target: `agent`, `sender`, and `recipient` take the stable name, and `messageId` takes the store id.\n- **Wait.** `wait` lists the records of `agent` in the complete form, read and unread records alike, until a record whose store id exceeds `afterId` is present or `timeoutSeconds` passes. Pass the id of the last record handled, or `0` for none, so a run that ends at any point loses no record. `data.outcome` is `received` with the first such `record`, `timeout` when none arrived in time, or `unreachable` when the listing cannot reach back to `afterId`; the store's labels reach the result in `response` as for `list`. A request without `timeoutSeconds` is `invalid-schema` before any store command runs, `timeoutSeconds` is a whole number from 1 to 3600, and no store command outlives it. A wait keeps no cursor, state file, or lock, and changes no record's read state; judge a record with `read` or `acknowledge`. An `unreachable` outcome means the record after `afterId` cannot be told from the listing, so a later record is never returned in its place; reconcile with `list` and `allRecords`.\n- **Liveness.** No operation reports liveness, staleness, or session state, because the store's per-agent activity timestamp moves for reasons unrelated to a session being alive.\n- **Credential.** A registration leaves the credential the store keeps for that name, and the next send from that name authenticates through it. The store offers no separate credential command, so the adapter makes none and no step of this skill refreshes it.\n\nThe project key is the repository's own common Git directory, so every worktree of one pool, the pool's bare repository, and the pool's main checkout resolve one mail project, and no checkout's deletion removes it. The adapter reads that directory for the repository a request names, or for its own working directory when the request names none, before every operation and reads no other working directory, environment variable, or parent path in its place. The lookup drops every variable that could make Git answer from something other than that directory — one naming a repository and one bounding where Git may look are known cases, not the only ones — and carries every other through, so a repository reachable only across a mount boundary still resolves. A working directory that is no repository yields `repository-unresolved`.\n\n\u003C\u002Foperation_surface>\n\n\u003Cworkflow>\n\n1. Interpret `$ARGUMENTS` as one request operation with its arguments, or as a complete JSON request. When it is empty, run nothing and report that one operation from `\u003Coperation_surface>` is required; the adapter has no default operation. When it names `project-key`, take the CLI form in `\u003Cinvocation_forms>` and stop; steps 2 to 4 govern request operations only.\n2. Build this source-owned request shape and set only the arguments the operation accepts:\n\n   ```json\n   {\n     \"schemaVersion\": 1,\n     \"operation\": \"send\",\n     \"arguments\": {\n       \"record\": {\n         \"schema\": 1,\n         \"kind\": \"fact\",\n         \"correlation\": \"change-88-exec\",\n         \"sender\": \"AmberGull\",\n         \"recipient\": \"PeachFrog\",\n         \"subject\": \"changeset pushed\",\n         \"body\": \"Full commit SHA and branch, verbatim.\",\n         \"ackRequired\": true\n       }\n     }\n   }\n   ```\n\n   An operation that acts on another repository's store carries `\"repository\": \"\u003Cabsolute path>\"` beside its other `arguments`; omit it to act on the store of the adapter's own working directory.\n\n3. Write the request with the file-write tool to a file in the scratch directory the harness names for this session, under a file name unique to the agent and the request, and submit it through the input redirect in `\u003Cinvocation_forms>`. Where the harness names no scratch directory, use the one the environment designates, such as `$RUNNER_TEMP` on a hosted runner.\n4. For a `run` request, accept only `status: \"succeeded\"`, which exits zero and carries exactly seven fields, every one of them preserved: `schemaVersion`, `operation`, `status`, `commandExitCode`, `projectKey` (the key of the store the operation acted on), the store's `response`, and `data`. A delivered message is the `record` in `data` carrying its store-assigned `id`. A request the adapter read and rejected answers instead with `schemaVersion`, `operation` — the requested operation, or `unknown` where the request named none — `status` (`command-failed`, `invalid-schema`, `store-unavailable`, `repository-unresolved`, or `operation-unavailable`), `detail`, and `commandExitCode` where a store command returned an exit code, and exits 1. Stdin the adapter cannot read as a JSON object is rejected before any operation is read, so that answer carries `schemaVersion`, `operation` as `unknown`, `status: \"invalid-schema\"`, and `detail`, with no `commandExitCode`, and exits 2. A failure of the store command itself, of any class, answers `store-unavailable` or `command-failed` in the same versioned shape. Stop on the exact `status` and `detail` of every failing form; none of them admits a fallback command, key, or store. The `project-key` operation answers in its own shape, stated with its form below.\n\n\u003C\u002Fworkflow>\n\n\u003Cinvocation_forms>\n\nTo submit a request, with `\u003Crequest-file>` the file written in step 3:\n\n```bash\npython3 \"${CLAUDE_SKILL_DIR}\u002Fscripts\u002Fagent_mail.py\" run \u003C \u003Crequest-file>\n```\n\nTo read the project key alone, for the adapter's own working directory:\n\n```bash\npython3 \"${CLAUDE_SKILL_DIR}\u002Fscripts\u002Fagent_mail.py\" project-key\n```\n\nTo read the key of another repository, add the option `--repository \u003Cabsolute-path>`; the form then answers that repository's key, or `repository-unresolved` when the path resolves to no repository, and never the key of its own working directory.\n\n```bash\npython3 \"${CLAUDE_SKILL_DIR}\u002Fscripts\u002Fagent_mail.py\" project-key --repository \u003Cabsolute-path>\n```\n\nThis form answers `{\"projectKey\": \"\u003Cabsolute path>\"}` and exits zero, or `{\"status\": \"repository-unresolved\", \"detail\": \"\u003Creason>\"}` and exits non-zero. It carries no `schemaVersion`, `status` on success, `commandExitCode`, `response`, or `data`, because it runs no store command.\n\n\u003C\u002Finvocation_forms>\n\n\u003Cconstraints>\n\n- ALWAYS execute the bundled script through `${CLAUDE_SKILL_DIR}` — the skill loader substitutes that expression into this body before the command runs, so only this spelling reaches the shell as this skill's real directory.\n- NEVER import the script from another filesystem location or manufacture a path outside this skill directory — the substituted expression is the only route that resolves.\n- NEVER copy `${CLAUDE_SKILL_DIR}` into an agent definition or export it — it is no shell variable, so outside this body it yields an empty prefix rather than an error.\n- ALWAYS preserve store identities verbatim: message ids, thread ids, agent names, and timestamps, because downstream skills index on the literal and the operator compares it against the store.\n- ALWAYS hold a bounded wait to one invocation and re-arm it with the id of the last record handled; the adapter loops only inside its timeout.\n- ALWAYS supply arguments under the field names in `\u003Coperation_surface>` and leave the mapping to the adapter: it alone turns a field into an `am` option or a store field and reads it back, and it rejects an argument outside the operation's shape as `invalid-schema` rather than dropping it.\n- ALWAYS register a position's own stable name only, with that position's own label when it has one; register no other name and no other position's label.\n- NEVER select, route, or address by a label; the stable name or the store id selects every target, and a label may be shared by two agents and changes with its owner.\n- NEVER pass a request through a heredoc, a pipe, or an inline argument, and NEVER remove the request file — a request carries code spans, quotes, and JSON that the dangerous-command guard refuses in those forms, and the harness clears its scratch directory.\n- NEVER invoke raw `am` commands, `am` command help, or read the store's database.\n- NEVER derive the project key outside the adapter; it reads the key from the repository a request names, or from its own working directory when none is named, and no other working directory, environment variable, or parent path stands in for it.\n- NEVER treat a read or an acknowledgement as agreement, ownership, authorization, or acceptance of a proposal; it records only that the recipient judged one message, and says nothing about its content.\n- NEVER read or acknowledge a record on another recipient's behalf, and NEVER acknowledge when a private `read` suffices.\n- NEVER report or relay the registration token the store returns; the adapter removes it from every result.\n\n\u003C\u002Fconstraints>\n\n\u003Ctesting>\n\nThe bundled adapter is covered over generated request, record, and repository-lookup domains, with controlled `CommandRunner` implementations at the command boundary and real repositories behind the repository lookup:\n\n- every operation accepts an optional `repository`, maps to the same store command under that repository's key, and reports that key as the result's `projectKey`, and the project-key form given `--repository` answers that repository's key;\n- a `repository` that is no absolute path string runs no store command, and a named path that resolves to no repository answers `repository-unresolved` rather than the key of the adapter's working directory;\n- every registry operation's argument vector is read against the store CLI's captured usage text under the resolved project key;\n- a real pool's linked worktree, bare repository, main checkout, and a symlinked route to one of them each resolve one key, while the pool's parent directory resolves none;\n- every environment variable Git's own behaviour confirms moves the answer off the working directory — by answering with another repository, or with none — leaves the key unchanged, each alone and all together, read from the pool shape whose lookup Git confirmed it moves, while the parent directory still resolves none;\n- a wait returns the first record past its id, read or unread, as a `received` outcome, a `timeout` outcome when none arrives, and an `unreachable` outcome for a full listing that does not reach back to the id, under a controlled clock;\n- `list` maps to the store's non-marking listing in its unjudged form, or its complete form with `allRecords`, and `read` and `acknowledge` each map to their own store command, never to each other's;\n- a list, a wait, and every operation other than `read` and `acknowledge` leave read state unchanged;\n- a wait without a timeout runs no store command, no store command inside a wait is given more time than remains, and a wait leaves no cursor, state file, or lock and runs neither a read nor an acknowledgement command;\n- generated records round-trip through the store field mapping, including correlations the store's thread alphabet rejects, which round-trip through the `xc-` escape;\n- a correlation whose written thread id exceeds 128 characters and a text argument carrying a NUL byte are rejected before any store command runs;\n- every emitted result, including the failure of unparseable input, carries the versioned shape, and a runner error of any class maps to `store-unavailable` or `command-failed`;\n- a second terminal handback of the same kind with different content is rejected as a conflicting handback naming the difference;\n- a raw `am` command is recognized in argument-vector and shell-string form;\n- an `order`, its `delegation-request`, and its one correlated terminal handback are delivered through this capability's own send path;\n- repeated and conflicting terminal handbacks reduce to one result;\n- the CLI run where no executable resolves returns `repository-unresolved` with no fallback, for every operation;\n- every operation completes where only the adapter's own programs resolve;\n- a captured registration response reaches the result without its token;\n- a registration request's display name reaches the store as its label, and a request without one passes none;\n- the store's `sender_display_name` on listed records with and without bodies and on send results, `null` included, and `to_display_names` on send results reach the result verbatim beside the message, with no label inside the record;\n- a label carried in a target position is passed as the identity and never resolved, and a store label never selects the sender or recipient of a record.\n\n\u003C\u002Ftesting>\n\n\u003Cfailure_modes>\n\n**A store keyed under the earlier derivation read back as an empty list.** Claude listed the records of an agent that had been registered before the project key moved from the pool's main checkout path to the repository's own common Git directory, and took the empty result as \"no messages\". The registrations and message records were still in the store under the previous key, so the read was addressing a different project. A list that reads back empty for an agent known to be registered is a key mismatch rather than an absent-message state: re-register the agent under the current key with `register` before reading an empty result as an answer. Carrying the earlier project's records into the current key is no operation in `\u003Coperation_surface>`; it is a store-side change, so report the mismatch and the two keys and leave that change to whoever operates the store.\n\n\u003C\u002Ffailure_modes>\n\n\u003Csuccess_criteria>\n\n- A successful `run` operation is established only when the bundled script exits zero and emits exactly the seven fields of the versioned success result — `schemaVersion: 1`, `operation`, `status: \"succeeded\"`, `commandExitCode: 0`, `projectKey`, `response`, and `data` — without exposing `am` command grammar; a successful `project-key` operation is established only when it exits zero and emits `projectKey`.\n- Every record sent and read back carries the same `schema`, `kind`, `correlation`, `sender`, `recipient`, `subject`, `body`, and `ackRequired`, plus the store-assigned `id` on read.\n- A request naming a `repository` acts on that repository's store, and its result's `projectKey` is that repository's key.\n- An absent store or an unresolvable repository yields its named unavailable result and no fallback.\n- No registration result carries the store's registration token.\n- A wait ends with exactly one of the named outcomes `received`, `timeout`, or `unreachable`, never with a record at or below its `afterId`.\n- A label the store returns reaches the result verbatim beside its message, and no target is selected by it.\n- A `list`, a `wait`, or any operation other than `read` and `acknowledge` leaves every record's read state as it found it.\n\n\u003C\u002Fsuccess_criteria>\n","\u003Cobjective>\nA versioned JSON agent-mail operation result — a registered identity, a delivered record with its store-assigned id, the recipient's listed records, the message a read or an acknowledgement judged, or the first later record or a named timeout or unreachable outcome of a bounded wait — under the project key of the store the operation acted on, or that key alone as an unversioned `projectKey` answer, with every store identity preserved verbatim.\n\u003C\u002Fobjective>\n\n\u003Coperation_surface>\n\nThe source-owned request operations, each submitted as a JSON request to `run`:\n\n| Operation     | Arguments                                                   | Result data                                                               |\n| ------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------- |\n| `register`    | `agent`, `program`, `model`; optional `task`, `displayName` | the registered `agent` name and store id                                  |\n| `send`        | `record`                                                    | the `record` with its store-assigned `id`                                 |\n| `list`        | `agent`; optional `allRecords`, `includeBodies`, `limit`    | `records` listed for that recipient                                       |\n| `read`        | `agent`, `messageId`                                        | the `agent` and `messageId` the recipient judged                          |\n| `acknowledge` | `agent`, `messageId`                                        | the `agent` and `messageId` the sender can now see judged                 |\n| `wait`        | `agent`, `afterId`, `timeoutSeconds`                        | an `outcome` of `received` with the `record`, `timeout`, or `unreachable` |\n\nOne further form answers outside the request shape, so it takes no JSON request and the request-building steps of `\u003Cworkflow>` do not reach it. A `run` request naming it is rejected as `operation-unavailable`; its command is in `\u003Cinvocation_forms>`.\n\n| CLI form      | Arguments | Result data  |\n| ------------- | --------- | ------------ |\n| `project-key` | none      | `projectKey` |\n\nThe record and its delivery rules:\n\n- **Repository.** Every operation accepts an optional `repository` in its `arguments`, an absolute path string. The operation then acts on the store under the project key of that repository; a request naming none acts on the store of the adapter's own working directory. A value that is no string or no absolute path is rejected as `invalid-schema` before any command runs, and a path that resolves to no repository answers `repository-unresolved`, never the key of the adapter's own working directory. The adapter reads no overlay or configuration to select a repository; the request names it. The result's `projectKey` reports the store the operation acted on.\n- **No registration on behalf.** The adapter registers no identity for a caller: a send from a name the named store does not hold returns the store's failure as `command-failed`, and `register` against that repository creates the identity.\n- **Fields.** A `record` carries exactly `schema` (`1`), `kind`, `correlation`, `sender`, `recipient`, `subject`, `body`, and `ackRequired`; the store assigns `id` on delivery.\n- **Kinds a sender writes.** `order`, `fact`, `question`, `answer`, `delegation-request`, and the four terminal handbacks `delegation-completed`, `delegation-failed`, `delegation-rejected`, and `delegation-unavailable`. On read-back the adapter reports each record's kind as one of those or as `unclassified`, and `subject` carries the text to use in either case. Never derive a kind from a subject: the adapter owns the prefix it writes and the conditions a row meets to classify, and a row missing any of them reads as `unclassified` with its subject verbatim.\n- **Mapping.** The adapter maps `correlation` onto the store's thread, `kind` onto a subject prefix, and `ackRequired` onto the store's acknowledgement requirement, and reads each back; a store limit never shapes the record. A correlation the store's thread alphabet rejects — one with a character outside letters, digits, `.`, `_`, and `-`, a non-alphanumeric first character, or the prefix `xc-` — travels as an `xc-` escape the adapter writes and reads back to the original correlation, so any correlation round-trips. A correlation whose written thread id would exceed 128 characters is rejected as `invalid-schema` before any command runs, and so is any text argument carrying a NUL byte.\n- **Read state.** Only `read` and `acknowledge` change a record's read state. `list` and `wait` change none, so looking at records never judges them. `read` records, visibly to the recipient alone, that the recipient judged one message. `acknowledge` is a read the sender can observe. Neither stands in for the other: use `read` for a private judgment and `acknowledge` only when the sender is meant to see it.\n- **List.** `list` returns the records the recipient has not yet judged; with `allRecords` true it returns every record, read or unread. A request carrying `unreadOnly` is rejected as `invalid-schema`.\n- **One recipient.** `recipient` names one agent. A value carrying the store's `,` separator is rejected with `invalid-schema` before any command runs.\n- **Foreign rows.** A row another sender wrote reads back rather than failing the listing: without a thread it reads with `correlation: null`, classified by the kind rule above, and `ackRequired` is true for an acknowledgement status of `required`, `pending`, or `acked` and false for every other status. A thread id that is no escape the adapter writes reads back verbatim as `correlation`. A row without the store's `id`, `from`, or `subject` key is a malformed store response and fails the read as `invalid-schema`.\n- **Labels.** A position label is the display name the store records for an agent. `register` passes an optional `displayName` to the store as the agent's label and registers only the `agent` name the request supplies. A listed record, with or without a body, and a send result carry the store's `sender_display_name` verbatim in `response` beside the message, `null` when the sender has no label; a send result also carries `to_display_names`, which maps each recipient's stable name visible to the reader to its label. No label enters the `record`. A label names no target: `agent`, `sender`, and `recipient` take the stable name, and `messageId` takes the store id.\n- **Wait.** `wait` lists the records of `agent` in the complete form, read and unread records alike, until a record whose store id exceeds `afterId` is present or `timeoutSeconds` passes. Pass the id of the last record handled, or `0` for none, so a run that ends at any point loses no record. `data.outcome` is `received` with the first such `record`, `timeout` when none arrived in time, or `unreachable` when the listing cannot reach back to `afterId`; the store's labels reach the result in `response` as for `list`. A request without `timeoutSeconds` is `invalid-schema` before any store command runs, `timeoutSeconds` is a whole number from 1 to 3600, and no store command outlives it. A wait keeps no cursor, state file, or lock, and changes no record's read state; judge a record with `read` or `acknowledge`. An `unreachable` outcome means the record after `afterId` cannot be told from the listing, so a later record is never returned in its place; reconcile with `list` and `allRecords`.\n- **Liveness.** No operation reports liveness, staleness, or session state, because the store's per-agent activity timestamp moves for reasons unrelated to a session being alive.\n- **Credential.** A registration leaves the credential the store keeps for that name, and the next send from that name authenticates through it. The store offers no separate credential command, so the adapter makes none and no step of this skill refreshes it.\n\nThe project key is the repository's own common Git directory, so every worktree of one pool, the pool's bare repository, and the pool's main checkout resolve one mail project, and no checkout's deletion removes it. The adapter reads that directory for the repository a request names, or for its own working directory when the request names none, before every operation and reads no other working directory, environment variable, or parent path in its place. The lookup drops every variable that could make Git answer from something other than that directory — one naming a repository and one bounding where Git may look are known cases, not the only ones — and carries every other through, so a repository reachable only across a mount boundary still resolves. A working directory that is no repository yields `repository-unresolved`.\n\n\u003C\u002Foperation_surface>\n\n\u003Cworkflow>\n\n1. Interpret `$ARGUMENTS` as one request operation with its arguments, or as a complete JSON request. When it is empty, run nothing and report that one operation from `\u003Coperation_surface>` is required; the adapter has no default operation. When it names `project-key`, take the CLI form in `\u003Cinvocation_forms>` and stop; steps 2 to 4 govern request operations only.\n2. Build this source-owned request shape and set only the arguments the operation accepts:\n\n   ```json\n   {\n     \"schemaVersion\": 1,\n     \"operation\": \"send\",\n     \"arguments\": {\n       \"record\": {\n         \"schema\": 1,\n         \"kind\": \"fact\",\n         \"correlation\": \"change-88-exec\",\n         \"sender\": \"AmberGull\",\n         \"recipient\": \"PeachFrog\",\n         \"subject\": \"changeset pushed\",\n         \"body\": \"Full commit SHA and branch, verbatim.\",\n         \"ackRequired\": true\n       }\n     }\n   }\n   ```\n\n   An operation that acts on another repository's store carries `\"repository\": \"\u003Cabsolute path>\"` beside its other `arguments`; omit it to act on the store of the adapter's own working directory.\n\n3. Write the request with the file-write tool to a file in the scratch directory the harness names for this session, under a file name unique to the agent and the request, and submit it through the input redirect in `\u003Cinvocation_forms>`. Where the harness names no scratch directory, use the one the environment designates, such as `$RUNNER_TEMP` on a hosted runner.\n4. For a `run` request, accept only `status: \"succeeded\"`, which exits zero and carries exactly seven fields, every one of them preserved: `schemaVersion`, `operation`, `status`, `commandExitCode`, `projectKey` (the key of the store the operation acted on), the store's `response`, and `data`. A delivered message is the `record` in `data` carrying its store-assigned `id`. A request the adapter read and rejected answers instead with `schemaVersion`, `operation` — the requested operation, or `unknown` where the request named none — `status` (`command-failed`, `invalid-schema`, `store-unavailable`, `repository-unresolved`, or `operation-unavailable`), `detail`, and `commandExitCode` where a store command returned an exit code, and exits 1. Stdin the adapter cannot read as a JSON object is rejected before any operation is read, so that answer carries `schemaVersion`, `operation` as `unknown`, `status: \"invalid-schema\"`, and `detail`, with no `commandExitCode`, and exits 2. A failure of the store command itself, of any class, answers `store-unavailable` or `command-failed` in the same versioned shape. Stop on the exact `status` and `detail` of every failing form; none of them admits a fallback command, key, or store. The `project-key` operation answers in its own shape, stated with its form below.\n\n\u003C\u002Fworkflow>\n\n\u003Cinvocation_forms>\n\nTo submit a request, with `\u003Crequest-file>` the file written in step 3:\n\n```bash\npython3 \"${CLAUDE_SKILL_DIR}\u002Fscripts\u002Fagent_mail.py\" run \u003C \u003Crequest-file>\n```\n\nTo read the project key alone, for the adapter's own working directory:\n\n```bash\npython3 \"${CLAUDE_SKILL_DIR}\u002Fscripts\u002Fagent_mail.py\" project-key\n```\n\nTo read the key of another repository, add the option `--repository \u003Cabsolute-path>`; the form then answers that repository's key, or `repository-unresolved` when the path resolves to no repository, and never the key of its own working directory.\n\n```bash\npython3 \"${CLAUDE_SKILL_DIR}\u002Fscripts\u002Fagent_mail.py\" project-key --repository \u003Cabsolute-path>\n```\n\nThis form answers `{\"projectKey\": \"\u003Cabsolute path>\"}` and exits zero, or `{\"status\": \"repository-unresolved\", \"detail\": \"\u003Creason>\"}` and exits non-zero. It carries no `schemaVersion`, `status` on success, `commandExitCode`, `response`, or `data`, because it runs no store command.\n\n\u003C\u002Finvocation_forms>\n\n\u003Cconstraints>\n\n- ALWAYS execute the bundled script through `${CLAUDE_SKILL_DIR}` — the skill loader substitutes that expression into this body before the command runs, so only this spelling reaches the shell as this skill's real directory.\n- NEVER import the script from another filesystem location or manufacture a path outside this skill directory — the substituted expression is the only route that resolves.\n- NEVER copy `${CLAUDE_SKILL_DIR}` into an agent definition or export it — it is no shell variable, so outside this body it yields an empty prefix rather than an error.\n- ALWAYS preserve store identities verbatim: message ids, thread ids, agent names, and timestamps, because downstream skills index on the literal and the operator compares it against the store.\n- ALWAYS hold a bounded wait to one invocation and re-arm it with the id of the last record handled; the adapter loops only inside its timeout.\n- ALWAYS supply arguments under the field names in `\u003Coperation_surface>` and leave the mapping to the adapter: it alone turns a field into an `am` option or a store field and reads it back, and it rejects an argument outside the operation's shape as `invalid-schema` rather than dropping it.\n- ALWAYS register a position's own stable name only, with that position's own label when it has one; register no other name and no other position's label.\n- NEVER select, route, or address by a label; the stable name or the store id selects every target, and a label may be shared by two agents and changes with its owner.\n- NEVER pass a request through a heredoc, a pipe, or an inline argument, and NEVER remove the request file — a request carries code spans, quotes, and JSON that the dangerous-command guard refuses in those forms, and the harness clears its scratch directory.\n- NEVER invoke raw `am` commands, `am` command help, or read the store's database.\n- NEVER derive the project key outside the adapter; it reads the key from the repository a request names, or from its own working directory when none is named, and no other working directory, environment variable, or parent path stands in for it.\n- NEVER treat a read or an acknowledgement as agreement, ownership, authorization, or acceptance of a proposal; it records only that the recipient judged one message, and says nothing about its content.\n- NEVER read or acknowledge a record on another recipient's behalf, and NEVER acknowledge when a private `read` suffices.\n- NEVER report or relay the registration token the store returns; the adapter removes it from every result.\n\n\u003C\u002Fconstraints>\n\n\u003Ctesting>\n\nThe bundled adapter is covered over generated request, record, and repository-lookup domains, with controlled `CommandRunner` implementations at the command boundary and real repositories behind the repository lookup:\n\n- every operation accepts an optional `repository`, maps to the same store command under that repository's key, and reports that key as the result's `projectKey`, and the project-key form given `--repository` answers that repository's key;\n- a `repository` that is no absolute path string runs no store command, and a named path that resolves to no repository answers `repository-unresolved` rather than the key of the adapter's working directory;\n- every registry operation's argument vector is read against the store CLI's captured usage text under the resolved project key;\n- a real pool's linked worktree, bare repository, main checkout, and a symlinked route to one of them each resolve one key, while the pool's parent directory resolves none;\n- every environment variable Git's own behaviour confirms moves the answer off the working directory — by answering with another repository, or with none — leaves the key unchanged, each alone and all together, read from the pool shape whose lookup Git confirmed it moves, while the parent directory still resolves none;\n- a wait returns the first record past its id, read or unread, as a `received` outcome, a `timeout` outcome when none arrives, and an `unreachable` outcome for a full listing that does not reach back to the id, under a controlled clock;\n- `list` maps to the store's non-marking listing in its unjudged form, or its complete form with `allRecords`, and `read` and `acknowledge` each map to their own store command, never to each other's;\n- a list, a wait, and every operation other than `read` and `acknowledge` leave read state unchanged;\n- a wait without a timeout runs no store command, no store command inside a wait is given more time than remains, and a wait leaves no cursor, state file, or lock and runs neither a read nor an acknowledgement command;\n- generated records round-trip through the store field mapping, including correlations the store's thread alphabet rejects, which round-trip through the `xc-` escape;\n- a correlation whose written thread id exceeds 128 characters and a text argument carrying a NUL byte are rejected before any store command runs;\n- every emitted result, including the failure of unparseable input, carries the versioned shape, and a runner error of any class maps to `store-unavailable` or `command-failed`;\n- a second terminal handback of the same kind with different content is rejected as a conflicting handback naming the difference;\n- a raw `am` command is recognized in argument-vector and shell-string form;\n- an `order`, its `delegation-request`, and its one correlated terminal handback are delivered through this capability's own send path;\n- repeated and conflicting terminal handbacks reduce to one result;\n- the CLI run where no executable resolves returns `repository-unresolved` with no fallback, for every operation;\n- every operation completes where only the adapter's own programs resolve;\n- a captured registration response reaches the result without its token;\n- a registration request's display name reaches the store as its label, and a request without one passes none;\n- the store's `sender_display_name` on listed records with and without bodies and on send results, `null` included, and `to_display_names` on send results reach the result verbatim beside the message, with no label inside the record;\n- a label carried in a target position is passed as the identity and never resolved, and a store label never selects the sender or recipient of a record.\n\n\u003C\u002Ftesting>\n\n\u003Cfailure_modes>\n\n**A store keyed under the earlier derivation read back as an empty list.** Claude listed the records of an agent that had been registered before the project key moved from the pool's main checkout path to the repository's own common Git directory, and took the empty result as \"no messages\". The registrations and message records were still in the store under the previous key, so the read was addressing a different project. A list that reads back empty for an agent known to be registered is a key mismatch rather than an absent-message state: re-register the agent under the current key with `register` before reading an empty result as an answer. Carrying the earlier project's records into the current key is no operation in `\u003Coperation_surface>`; it is a store-side change, so report the mismatch and the two keys and leave that change to whoever operates the store.\n\n\u003C\u002Ffailure_modes>\n\n\u003Csuccess_criteria>\n\n- A successful `run` operation is established only when the bundled script exits zero and emits exactly the seven fields of the versioned success result — `schemaVersion: 1`, `operation`, `status: \"succeeded\"`, `commandExitCode: 0`, `projectKey`, `response`, and `data` — without exposing `am` command grammar; a successful `project-key` operation is established only when it exits zero and emits `projectKey`.\n- Every record sent and read back carries the same `schema`, `kind`, `correlation`, `sender`, `recipient`, `subject`, `body`, and `ackRequired`, plus the store-assigned `id` on read.\n- A request naming a `repository` acts on that repository's store, and its result's `projectKey` is that repository's key.\n- An absent store or an unresolvable repository yields its named unavailable result and no fallback.\n- No registration result carries the store's registration token.\n- A wait ends with exactly one of the named outcomes `received`, `timeout`, or `unreachable`, never with a record at or below its `afterId`.\n- A label the store returns reaches the result verbatim beside its message, and no target is selected by it.\n- A `list`, a `wait`, or any operation other than `read` and `acknowledge` leaves every record's read state as it found it.\n\n\u003C\u002Fsuccess_criteria>\n",{"name":5,"description":7,"allowed-tools":49,"argument-hint":50},"Write, Bash(python3 \"${CLAUDE_SKILL_DIR}\u002Fscripts\u002Fagent_mail.py\":*)","\u003Coperation or JSON request>","main","978d51c51d68c99cffb2ba48f7cad9d2f07e5738","src\u002Fplugins\u002Fcoding-agents\u002Fskills\u002Foperate-agent-mail","https:\u002F\u002Fgithub.com\u002Foutcomeeng\u002Fplugins","https:\u002F\u002Fgithub.com\u002Foutcomeeng","https:\u002F\u002Foutcome.engineering","Spec-driven development for AI-assisted engineering","2026-11-11 22:17:26",{"source":8,"skillName":5,"commands":60,"prompt":70,"zipAvailable":71},[61,64,67],{"tool":62,"command":63},"npx","npx skills add outcomeeng\u002Fplugins --skill operate-agent-mail",{"tool":65,"command":66},"bunx","bunx skills add outcomeeng\u002Fplugins --skill operate-agent-mail",{"tool":68,"command":69},"pnpm","pnpm dlx skills add outcomeeng\u002Fplugins --skill operate-agent-mail","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Foutcomeeng\u002Fplugins\u002Fblob\u002Fmain\u002Fsrc\u002Fplugins\u002Fcoding-agents\u002Fskills\u002Foperate-agent-mail\u002FSKILL.md",true,[73],{"path":74,"resourceType":75,"resourceTypeDesc":76,"sizeBytes":77,"sourceHtmlUrl":78},"scripts\u002Fagent_mail.py","SCRIPT","脚本",62181,"https:\u002F\u002Fgithub.com\u002Foutcomeeng\u002Fplugins\u002Fblob\u002Fmain\u002Fsrc\u002Fplugins\u002Fcoding-agents\u002Fskills\u002Foperate-agent-mail\u002Fscripts\u002Fagent_mail.py",[80,86,118,133,150,163],{"skillNo":81,"name":82,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":85,"publishedAt":44},"01M71G25RZTPQG9KJ00JCHC1F7","plugin","https:\u002F\u002Fgithub.com\u002Foutcomeeng\u002Fplugins\u002Fblob\u002Fmain\u002Fsrc\u002Ftemplates\u002Fplugin\u002FSKILL.md",[],[82],{"skillNo":87,"name":88,"nameZh":6,"description":89,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":100,"publishedAt":44},"01M71G23DCX3SV60H63HBBKQ6J","sanitize-powerpoint","ALWAYS invoke this skill when sanitizing, cleaning up, auditing, or aligning a PowerPoint (.pptx) deck — slide-master and layout structure, layout type attributes, stray fonts, non-theme colors, or layout naming. NEVER hand-edit pptx XML without this skill.","https:\u002F\u002Fgithub.com\u002Foutcomeeng\u002Fplugins\u002Fblob\u002Fmain\u002Fsrc\u002Fplugins\u002Fwork\u002Fskills\u002Fsanitize-powerpoint\u002FSKILL.md",[92,95],{"categoryNo":93,"categoryName":94,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000003","演示文稿",{"categoryNo":96,"categoryName":97,"taxonomyType":98,"taxonomyTypeDesc":99},"01JBSEEDCAT000000000000034","行政与办公人员","PROFESSION","适用职业",[101,102,103,104,105,106,107,39,108,109,110,111,112,113,114,115,116,117,29,28],"sanitize powerpoint","powerpoint","sanitize","fonts","type","cleaning","structure","attributes","theme","pptx","naming","layout","deck","up","edit","xml","master",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":44},"01M71G21PQKBCDECHGVYSKPJW5","draw-excalidraw","ALWAYS invoke this skill when creating Excalidraw diagrams, visualizing workflows, architectures, or concepts. NEVER generate Excalidraw JSON without this skill.","https:\u002F\u002Fgithub.com\u002Foutcomeeng\u002Fplugins\u002Fblob\u002Fmain\u002Fsrc\u002Fplugins\u002Fwork\u002Fskills\u002Fdraw-excalidraw\u002FSKILL.md",[],[125,126,127,128,129,39,29,130,131,28,132,34],"draw excalidraw","excalidraw","draw","diagrams","architectures","generate","workflows","concepts",{"skillNo":134,"name":135,"nameZh":6,"description":136,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":137,"categories":138,"keywords":142,"publishedAt":44},"01M71G1ZMNGFD37RZYM620XM2C","typescript-test-standards","TypeScript test standards enforced across all skills. Loaded by other skills, not invoked directly.","https:\u002F\u002Fgithub.com\u002Foutcomeeng\u002Fplugins\u002Fblob\u002Fmain\u002Fsrc\u002Fplugins\u002Ftypescript\u002Fskills\u002Ftypescript-test-standards\u002FSKILL.md",[139],{"categoryNo":140,"categoryName":141,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",[143,144,145,146,147,148,149],"typescript","typescript test standards","test","standards","false","read","across",{"skillNo":151,"name":152,"nameZh":6,"description":153,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":154,"categories":155,"keywords":159,"publishedAt":44},"01M71G1XBH0X1VCTR7269MDGSY","typescript-code-standards","TypeScript code standards enforced across all skills. Loaded by other skills, not invoked directly.","https:\u002F\u002Fgithub.com\u002Foutcomeeng\u002Fplugins\u002Fblob\u002Fmain\u002Fsrc\u002Fplugins\u002Ftypescript\u002Fskills\u002Ftypescript-code-standards\u002FSKILL.md",[156],{"categoryNo":157,"categoryName":158,"taxonomyType":98,"taxonomyTypeDesc":99},"01JBSEEDCAT000000000000030","开发工程师",[143,160,161,162,146,147,148,149],"code","typescript code standards","code standards",{"skillNo":164,"name":165,"nameZh":6,"description":166,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":167,"categories":168,"keywords":169,"publishedAt":44},"01M71G1TQ3VN45SJ75DFMJDB9W","typescript-architecture-standards","TypeScript ADR conventions enforced across architect and auditor skills. Loaded by other skills, not invoked directly.","https:\u002F\u002Fgithub.com\u002Foutcomeeng\u002Fplugins\u002Fblob\u002Fmain\u002Fsrc\u002Fplugins\u002Ftypescript\u002Fskills\u002Ftypescript-architecture-standards\u002FSKILL.md",[],[170,146,171,172,143,173,174,149,148,175,147,176],"architecture standards","typescript architecture standards","architecture","adr","architect","auditor","conventions"]