simple-agent-extension 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +16 -0
  3. data/.standard.yml +5 -0
  4. data/AGENTS.md +29 -0
  5. data/CHANGELOG.md +19 -0
  6. data/LICENSE +24 -0
  7. data/README.md +215 -0
  8. data/Rakefile +43 -0
  9. data/adr/adr-0001-single-source-multi-agent-compilation.md +118 -0
  10. data/adr/adr-0002-source-package-model-and-metadata-dsl.md +92 -0
  11. data/adr/adr-0003-compile-time-artifact-scope.md +67 -0
  12. data/adr/adr-0004-external-agents-and-run-time-agent-selection.md +78 -0
  13. data/config/geminabox.ru +9 -0
  14. data/exe/simple-agent-extension +8 -0
  15. data/lib/simple-agent-extension.rb +1 -0
  16. data/lib/simple_agent_extension/agent_base.rb +119 -0
  17. data/lib/simple_agent_extension/agent_directory_loader.rb +60 -0
  18. data/lib/simple_agent_extension/agent_property/deployment.rb +23 -0
  19. data/lib/simple_agent_extension/agent_property/metadata_translator.rb +55 -0
  20. data/lib/simple_agent_extension/agent_property/skill.rb +29 -0
  21. data/lib/simple_agent_extension/agent_property.rb +8 -0
  22. data/lib/simple_agent_extension/agent_registry.rb +99 -0
  23. data/lib/simple_agent_extension/agents/claude_code.rb +62 -0
  24. data/lib/simple_agent_extension/agents/copilot.rb +30 -0
  25. data/lib/simple_agent_extension/agents/opencode.rb +35 -0
  26. data/lib/simple_agent_extension/agents.rb +11 -0
  27. data/lib/simple_agent_extension/cli.rb +145 -0
  28. data/lib/simple_agent_extension/collector.rb +86 -0
  29. data/lib/simple_agent_extension/compiler.rb +185 -0
  30. data/lib/simple_agent_extension/deployer.rb +60 -0
  31. data/lib/simple_agent_extension/deployment_report.rb +52 -0
  32. data/lib/simple_agent_extension/extensions/agent.rb +23 -0
  33. data/lib/simple_agent_extension/extensions/base.rb +73 -0
  34. data/lib/simple_agent_extension/extensions/skill.rb +10 -0
  35. data/lib/simple_agent_extension/extensions.rb +29 -0
  36. data/lib/simple_agent_extension/frontmatter.rb +48 -0
  37. data/lib/simple_agent_extension/metadata.rb +27 -0
  38. data/lib/simple_agent_extension/metadata_composer.rb +32 -0
  39. data/lib/simple_agent_extension/metadata_loader.rb +63 -0
  40. data/lib/simple_agent_extension/runner.rb +95 -0
  41. data/lib/simple_agent_extension/version.rb +5 -0
  42. data/lib/simple_agent_extension.rb +23 -0
  43. data/packages/deep-review/agent/deep-design-reviewer.md +184 -0
  44. data/packages/deep-review/agent/metadata.yaml +9 -0
  45. data/packages/deep-review/skill/SKILL.md +122 -0
  46. data/packages/deep-review/skill/metadata.yaml +6 -0
  47. metadata +92 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d5b57957c947b2f4c126dca54b41f69e67d8d2cbfc3a9447a31bea468b03cf76
4
+ data.tar.gz: 2aafa730f3def389acfd18c2cec0807dfcd78aa1148199ca7a6129ab93fe7c49
5
+ SHA512:
6
+ metadata.gz: 6bcc677fcc9c6afe8f01f67e77b7a65e86fda1a45ea951a21a362eb88e8b3650ec34e90399292cb3b9b0dacdb082e8c8a5ea3bc0033dbf13f3476366ed4491f2
7
+ data.tar.gz: f86cf67049dbc0bb7c16ed8c708ebb2e4b6c903240f1f260a2d88eb4be75e8a60c3922550ac1c99962393f5dcacee17c6c6c2ea72780a890f304b4e6d9c78bbd
data/.rubocop.yml ADDED
@@ -0,0 +1,16 @@
1
+ require:
2
+ - standard
3
+ - standard-custom
4
+ - standard-performance
5
+ - rubocop-performance
6
+
7
+ inherit_gem:
8
+ standard: config/base.yml
9
+ standard-custom: config/base.yml
10
+ standard-performance: config/base.yml
11
+
12
+ AllCops:
13
+ TargetRubyVersion: 3.3
14
+ Exclude:
15
+ - vendor/**/*
16
+ - spec/vendor/**/*
data/.standard.yml ADDED
@@ -0,0 +1,5 @@
1
+ ruby_version: 3.3
2
+ ignore:
3
+ - vendor/**/*
4
+ - spec/vendor/**/*
5
+ - spec/tmp/**/*
data/AGENTS.md ADDED
@@ -0,0 +1,29 @@
1
+ # Test
2
+
3
+ ## Design
4
+
5
+ * prefer Unit Test
6
+ * prefer black-box testing
7
+ * prefer dependency-injection with test-specific (sub)class over test-double object ( not prohibitted that )
8
+ * prefer blank-slate with specific behavior over intricate complex real object
9
+ * don't replicate tests in E2E ( tests outside of unit tests ) that are already covered by unit tests
10
+ * group tests for a method using `desribe`
11
+ * specify the conditions in `describe` and the results in `it`
12
+ * avoid helper methods that hide the actual methods being called
13
+
14
+ ## Assertions
15
+
16
+ Use `power_assert` for test assertions. Prefer its block form for value and
17
+ behavior checks:
18
+
19
+ ```ruby
20
+ assert { actual == expected }
21
+ ```
22
+
23
+ Do not introduce Minitest matcher expectations such as `must_equal` or
24
+ `wont_equal`. Use Minitest's exception assertions only when the behavior under
25
+ test is raising an error, for example `assert_raises`.
26
+
27
+ # Ruby Style
28
+
29
+ Follow StandardRB for Ruby code style and linting.
data/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ ## [0.2.1] 2026-10-02
2
+
3
+ - feat: support Claude Code
4
+ - docs: add ADR
5
+
6
+ ## [0.2.0] 2026-10-01
7
+
8
+ - feat: `agents` subcommand
9
+ - feat: readable reploy results
10
+ - feat: `--agent` option and `deploy_to` DSL
11
+ - test: remove several dangerous or unnecessary tests
12
+
13
+ ## [0.1.0] 2026-09-30
14
+
15
+ - Initial Release
16
+
17
+ ## 2026-08-24
18
+
19
+ - Unreleased
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2026, Colorful Company,Inc.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,215 @@
1
+ # SimpleAgentExtension
2
+
3
+ `simple-agent-extension` compiles each single source package into Agent-specific artifacts and can deploy a fresh build to locally installed Agents.
4
+
5
+ ## Installation
6
+
7
+ Requires Ruby 3.3 or later.
8
+
9
+ The gem is not published to RubyGems.org yet, so install it from GitHub with Bundler:
10
+
11
+ ```ruby
12
+ # Gemfile
13
+ group :development do
14
+ gem "simple-agent-extension", github: "colorfulcompany/simple-agent-extension"
15
+ end
16
+ ```
17
+
18
+ ```sh
19
+ bundle install
20
+ ```
21
+
22
+ Then run the CLI through Bundler:
23
+
24
+ ```sh
25
+ bundle exec simple-agent-extension packages
26
+ ```
27
+
28
+ Pin a release with `tag:` so the checkout does not move:
29
+
30
+ ```ruby
31
+ gem "simple-agent-extension",
32
+ github: "colorfulcompany/simple-agent-extension",
33
+ tag: "v0.1.0"
34
+ ```
35
+
36
+ `branch:` and `ref:` are also available; note that `branch:` follows new commits rather than pinning.
37
+
38
+ ## Usage
39
+
40
+ ### Defining a package
41
+
42
+ A **package** is an author-owned unit under the source root. It holds one or more **extensions**, one per extension type:
43
+
44
+ ```text
45
+ packages/
46
+ └── awesome-package/ # package
47
+ ├── skill/ # extension (type: skill)
48
+ │ ├── SKILL.md # entrypoint
49
+ │ ├── metadata.yaml # compiler input, never distributed
50
+ │ └── references/ # bundled as-is
51
+ └── agent/ # extension (type: agent)
52
+ ├── awesome-worker.md
53
+ └── metadata.yaml
54
+ ```
55
+
56
+ - Supported extension types are `skill` and `agent`. Either may stand alone; a package does not need both.
57
+ - A `skill` entrypoint is always `SKILL.md`.
58
+ - An `agent` entrypoint is the single top-level `*.md` file. Anything other than exactly one is an error.
59
+ - Every other file under an extension directory is copied into the artifact unchanged, nested directories included. `metadata.yaml` is the one exception.
60
+
61
+ ### Extension metadata
62
+
63
+ `metadata.yaml` belongs to one extension. It sits beside that extension's entrypoint and is optional.
64
+
65
+ ```yaml
66
+ name: awesome-worker
67
+
68
+ deploy_to:
69
+ - opencode
70
+
71
+ adaptive:
72
+ permissions:
73
+ read: allow
74
+ edit: ask
75
+
76
+ static:
77
+ common:
78
+ description: Short summary the Agent uses to decide when to load this extension.
79
+ agents:
80
+ opencode:
81
+ mode: subagent
82
+ ```
83
+
84
+ | Key | Meaning |
85
+ |---|---|
86
+ | `name` | Extension identity: the name the artifact is deployed under. |
87
+ | `deploy_to` | Agent names this extension is distributed to. Omitting the key distributes to every configured Agent. |
88
+ | `adaptive` | Source fragments whose artifact representation the selected Agent decides. An Agent that has a rule for the field rewrites it; a field with no rule passes through unchanged. |
89
+ | `static.common` | Written to every Agent's artifact without adaptation. |
90
+ | `static.agents.<agent>` | Written only to that Agent's artifact, without adaptation. |
91
+
92
+ `adaptive` does not mean dynamic. The value is fixed in the file; the key declares that the artifact representation belongs to the Agent rather than to the author.
93
+
94
+ #### Distribution targets
95
+
96
+ `deploy_to` limits which Agents an extension reaches.
97
+
98
+ - No build artifact is produced for an Agent the extension does not name.
99
+ - An extension carrying `deploy_to` is never written to the shared directory. That directory is read by every Agent, so sharing would undo the limit.
100
+
101
+ #### Name resolution
102
+
103
+ The extension identity is resolved in this order, later winning:
104
+
105
+ ```text
106
+ package directory name
107
+ < entrypoint frontmatter `name`
108
+ < metadata.yaml top-level `name`
109
+ ```
110
+
111
+ #### Metadata precedence
112
+
113
+ Artifact frontmatter is composed in this order, later winning:
114
+
115
+ ```text
116
+ entrypoint frontmatter
117
+ < static.common
118
+ < Agent-specific adapted fragments (from `adaptive`)
119
+ < static.agents.<agent>
120
+ ```
121
+
122
+ #### Adaptation across Agents
123
+
124
+ One `adaptive` fragment becomes different artifact metadata per Agent. The `permissions` fragment above compiles to:
125
+
126
+ | Agent | Artifact metadata |
127
+ |---|---|
128
+ | `claude` | agent: `tools: Read, Edit`; skill: `allowed-tools: Read` |
129
+ | `copilot` | `tools: [read]` |
130
+ | `opencode` | `permission: {read: allow, edit: ask}` |
131
+
132
+ `claude` maps known lowercase tool names such as `read` and `webfetch` to Claude Code's names (`Read`, `WebFetch`) and passes any other name through unchanged. `deny` becomes `disallowedTools` on an agent and `disallowed-tools` on a skill. An agent's `tools` lists both `allow` and `ask` tools, because Claude Code's `tools` limits which tools exist rather than pre-approving them.
133
+
134
+ A skill whose metadata is left unchanged by adaptation and carries no Agent-specific static fragments is written once to the shared skill directory. Otherwise it is written into that Agent's own configuration tree ( written with Ruby ). An agent extension is always Agent-specific. `claude` does not read the shared skill directory, so its skills are always written to `~/.claude/skills`.
135
+
136
+ ### Commands
137
+
138
+ `-h` / `--help` lists every command with a one-line summary.
139
+
140
+ snapshot as below:
141
+
142
+ ```sh
143
+ simple-agent-extension packages
144
+ simple-agent-extension build
145
+ simple-agent-extension deploy
146
+ simple-agent-extension agents
147
+ ```
148
+
149
+ All commands resolve `--source-root` from `./packages` and `--build-root` from `./build` by default. Either root may be outside the repository.
150
+
151
+ ```sh
152
+ simple-agent-extension deploy \
153
+ --source-root /work/extensions/packages \
154
+ --build-root /work/extensions/build \
155
+ --agent opencode
156
+ ```
157
+
158
+ `--agent NAME` is repeatable, matching the list shape of `deploy_to`. Without it, every configured Agent is targeted. Unlike `deploy_to`, a name no configured Agent answers to stops the command.
159
+
160
+ ```sh
161
+ simple-agent-extension build --agent copilot --agent opencode
162
+ ```
163
+
164
+ `--agent` narrows which Agents a run operates on. It does not declare distribution, so it does not change an artifact's scope.
165
+
166
+ `--force` is valid only with `deploy`. It creates deployment directories for an Agent whose configuration root is not already present.
167
+
168
+ ### External Agent registrations
169
+
170
+ Pass `--agent-dir DIRECTORY` one or more times to load trusted local Agent definitions.
171
+
172
+ - Only direct `*.rb` children are loaded; subdirectories are ignored.
173
+ - Each file must be self-contained. A registration cannot define an Agent that refers to an Agent defined in a sibling file, such as a subclass of one. Load order is an implementation detail, so such a definition is unsupported even when a particular filename ordering happens to make it load.
174
+ - Each loaded file must add a new `SimpleAgentExtension::Agents::*` subclass of `SimpleAgentExtension::AgentBase`.
175
+ - Duplicate Agent names and registration failures stop the command before build or deploy begins.
176
+
177
+ Agent registrations are executable Ruby and are not sandboxed. Do not load untrusted directories.
178
+
179
+ ## Development
180
+
181
+ ### Repository tasks
182
+
183
+ `Rakefile` is for development tasks:
184
+
185
+ ```sh
186
+ bundle exec rake spec
187
+ bundle exec standardrb
188
+ ```
189
+
190
+ ### Local gem source
191
+
192
+ Geminabox is a development-only dependency that serves the public Compact Index API locally. It is for package verification and does not become a runtime dependency of `simple-agent-extension`.
193
+
194
+ Start the loopback-only server in one terminal:
195
+
196
+ ```sh
197
+ bundle exec rake geminabox:start
198
+ ```
199
+
200
+ In another terminal, build and publish the local package:
201
+
202
+ ```sh
203
+ bundle exec rake geminabox:push
204
+ ```
205
+
206
+ Then install it from the local source in an isolated gem home if desired:
207
+
208
+ ```sh
209
+ gem_home="$(mktemp -d)"
210
+ GEM_HOME="$gem_home" GEM_PATH="$gem_home" \
211
+ gem install --clear-sources --source http://127.0.0.1:9292 \
212
+ --no-document simple-agent-extension
213
+ ```
214
+
215
+ Set `GEMINABOX_DATA`, `GEMINABOX_PORT`, or `GEMINABOX_URL` to use a non-default temporary location or port.
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+ require "yard/rake/yardoc_task"
6
+ require "standard/rake"
7
+
8
+ Minitest::TestTask.create(:spec) do |t|
9
+ t.libs.concat(%w[lib spec])
10
+ t.test_globs = [File.join(__dir__, "spec/**/*_spec.rb")]
11
+ end
12
+
13
+ namespace :geminabox do
14
+ desc "Start a loopback-only local Geminabox server"
15
+ task :start do
16
+ data = ENV.fetch("GEMINABOX_DATA", File.join(__dir__, "tmp/geminabox"))
17
+ port = ENV.fetch("GEMINABOX_PORT", "9292")
18
+
19
+ exec(
20
+ {"GEMINABOX_DATA" => data},
21
+ "bundle", "exec", "rackup",
22
+ "--server", "puma",
23
+ "--host", "127.0.0.1",
24
+ "--port", port,
25
+ File.join(__dir__, "config/geminabox.ru")
26
+ )
27
+ end
28
+
29
+ desc "Build and publish the local package to Geminabox"
30
+ task :push do
31
+ artifact = File.join(__dir__, "tmp", "simple-agent-extension.gem")
32
+ url = ENV.fetch("GEMINABOX_URL", "http://127.0.0.1:9292")
33
+
34
+ mkdir_p File.dirname(artifact)
35
+ sh "gem", "build", "simple-agent-extension.gemspec", "--output", artifact
36
+ sh "bundle", "exec", "gem", "inabox", "--overwrite", "--host", url, artifact
37
+ end
38
+ end
39
+
40
+ YARD::Rake::YardocTask.new do |t|
41
+ end
42
+
43
+ task default: :spec
@@ -0,0 +1,118 @@
1
+ ---
2
+ title: "ADR-0001: Single-source の extension を compile して multi-agent に対応する"
3
+ status: "Accepted"
4
+ date: "2026-10-02"
5
+ authors: "T.Watanabe (maintainer)"
6
+ tags: ["architecture", "decision", "single-source", "multi-agent", "compile"]
7
+ supersedes: ""
8
+ superseded_by: ""
9
+ ---
10
+
11
+ # ADR-0001: Single-source の extension を compile して multi-agent に対応する
12
+
13
+ ## Status
14
+
15
+ Proposed | **Accepted** | Rejected | Superseded | Deprecated
16
+
17
+ ## Context
18
+
19
+ Copilot CLI、OpenCode、Claude Code などの coding agent 製品は、skill や subagent という概念をほぼ共通に持つ。ただし、表現方法は製品ごとに異なる。
20
+
21
+ - **ファイル名と配置先**: `<name>.agent.md` と `<name>.md`、`~/.copilot` と `~/.config/opencode` と `~/.claude` など。
22
+ - **metadata の語彙と意味**: 同じ「ツール権限」が `tools`、`permission`、`allowed-tools` / `disallowed-tools` になり、許可・確認・拒否の意味づけも異なる。
23
+ - **共通規約の範囲**: 共通の skill ディレクトリ(`~/.agents/skills`)を読む製品と読まない製品がある。subagent に共通規約はない。
24
+
25
+ 一方で、skill や subagent の本文(指示内容)は製品に依存しない。作者は一つの機能を一度だけ書き、複数の Agent で使いたい。製品ごとにコピーを手で保守すると、内容が少しずつずれ、どれが正なのか分からなくなる。
26
+
27
+ ### 用語
28
+
29
+ 本 ADR 群で使う基本的な用語を挙げる。
30
+
31
+ | 用語 | 意味 |
32
+ |---|---|
33
+ | Agent | Copilot CLI、OpenCode、Claude Code などの coding agent 製品。 |
34
+ | package | 作者が一つの機能として書く source のまとまり。一つ以上の extension を含む。 |
35
+ | extension | package を構成する type 別の要素(現在は skill または agent)。作者が書く single source の単位。 |
36
+ | artifact | extension を一つの Agent 向けに compile した結果。そのまま配置できる。 |
37
+ | Agent class | 一つの Agent 製品の規約(ファイル名、配置先、metadata の語彙)を知るツール側の class。 |
38
+
39
+ ## Decision
40
+
41
+ **Agent に依存しない single source を作者が書き、Agent ごとに compile して製品固有の artifact を得る。**
42
+
43
+ ```mermaid
44
+ flowchart LR
45
+ E["extension<br/>(single source)"] --> C((compile))
46
+ D["Agent class<br/>(one per product)"] --> C
47
+ C --> A1["artifact for Agent A"]
48
+ C --> A2["artifact for Agent B"]
49
+ C --> A3["artifact for Agent C"]
50
+ ```
51
+
52
+ 作者は「何をさせたいか」を extension として一つだけ書く。それを製品ごとに「どう表すか」は、製品ごとに一つあるツール側の Agent class が知っており、compile が両者を組み合わせて Agent ごとの artifact を作る。必要であれば、作者が Agent 固有の指定を extension に書き添えることもできる。extension の中身は ADR-0002 で定める。
53
+
54
+ ### 設計原則
55
+
56
+ 今後の変更はこれらの原則に従う。原則を変える場合は、本 ADR を置き換える新しい ADR を書く。ADR-0002 以降は、これらの原則を具体化したものである。
57
+
58
+ - **PRI-001 Single source**: extension を唯一の正とし、原則として Agent 非依存に書く。製品ごとのコピーは持たない。
59
+ - **PRI-002 製品の知識は Agent class に閉じる**: ファイル名、配置先、metadata の語彙といった製品間の差異は Agent class だけが知る。新しい製品への対応は Agent class の追加で行い、既存の extension や compile の流れは変えない。既存の extension を変えずにその製品向けの artifact が得られることを、対応できたことの基準とする。
60
+ - **PRI-003 Agent 固有の記述は metadata の決まった場所に限る**: 作者が Agent 固有の指定を書く必要がある場合は、metadata の決まった場所に書く(ADR-0002)。本文に製品ごとの分岐を持ち込まない。
61
+ - **PRI-004 本文は変換しない**: compile が変えるのは metadata(frontmatter)、ファイル名、配置先の分類だけである。本文と同梱ファイルはそのまま渡す。
62
+ - **PRI-005 metadata の翻訳は field 単位**: Agent class は `(type, field)` ごとの規則で、一つの field の値をその Agent の表現(0 個以上の field)に変える。規則のない field はそのまま通す。
63
+ - **PRI-006 変換と判断は compile で完結する**: compile 結果は配置可能な最終形の artifact である。配置時には変換も判断もしない。
64
+
65
+ ## Consequences
66
+
67
+ ### Positive
68
+
69
+ - **POS-001**: 一つの機能を一度書けば、対応するすべての Agent で使える。製品ごとのコピーがずれることもない。
70
+ - **POS-002**: 新しい Agent 製品への対応は Agent class の追加で済む。既存の source を書き換える必要はない。
71
+ - **POS-003**: 翻訳規則は一つの field に閉じた小さな変換なので、Agent ごとに独立してテストできる。
72
+ - **POS-004**: 作者は、多くの場合、製品固有の規約(ファイル名、配置先、権限の語彙)を覚えなくてよい。製品固有の機能を使いたいときだけ、該当 Agent 向けの metadata を書けばよい。
73
+ - **POS-005**: compile 結果を配置前に確認・diff できる。変換の問題と配置の問題を分けて調べられる。
74
+
75
+ ### Negative
76
+
77
+ - **NEG-001**: 作者とインストール先の間に変換工程が入る。利用には build と deploy が必要になる。
78
+ - **NEG-002**: 製品間で意味が完全には一致しない概念がある(例: Claude Code の subagent `tools` は許可と確認を区別しない)。compile の結果は近似になりうる。
79
+ - **NEG-003**: Agent 製品の仕様変更に合わせて、ツール側の Agent class を追従させ続ける必要がある。
80
+ - **NEG-004**: 本文は変換しないため、本文に製品固有の記述が必要な場合は単一の source では表現できない。
81
+ - **NEG-005**: 翻訳は field 単位のため、複数の field にまたがる変換は表現できない。複数の規則が同じ出力 field を生成した場合の扱いも未定義。
82
+
83
+ ## Alternatives Considered
84
+
85
+ ### 製品ごとに source を個別に保守
86
+
87
+ - **ALT-001**: **Description**: Agent ごとに skill / agent ファイルを用意し、手で同期する。
88
+ - **ALT-002**: **Rejection Reason**: 内容がずれやすく、正がどれか分からなくなる。対応製品が増えるほど保守の負担が増える。
89
+
90
+ ### 特定製品の形式を正として他製品へ変換
91
+
92
+ - **ALT-003**: **Description**: たとえば Copilot の形式で書き、そこから他の製品の形式を生成する。
93
+ - **ALT-004**: **Rejection Reason**: source の語彙が特定製品に縛られ、その製品の仕様変更が全体に波及する。他の製品にしかない表現も扱いにくい。
94
+
95
+ ### 共通規約(`~/.agents/skills` など)だけに依存
96
+
97
+ - **ALT-005**: **Description**: 変換を行わず、共通ディレクトリへのコピーや symlink だけで済ませる。
98
+ - **ALT-006**: **Rejection Reason**: 共通ディレクトリを読まない製品があり、subagent には共通規約もない。metadata の語彙の差も解消できない。
99
+
100
+ ### source 内に製品ごとの条件分岐を書く(テンプレート)
101
+
102
+ - **ALT-007**: **Description**: ERB などで `if agent == ...` のように本文や frontmatter を分岐させる。
103
+ - **ALT-008**: **Rejection Reason**: 製品の知識が本文を含む source 全体に広がり、本文が単体で読める文書でなくなる。Agent 固有の記述は metadata の決まった場所(`static.agents.<agent>`)に限る方がよい。
104
+
105
+ ### metadata 全体を受け取る翻訳器
106
+
107
+ - **ALT-009**: **Description**: Agent class が metadata 全体を受け取り、最終的な frontmatter を組み立てる。
108
+ - **ALT-010**: **Rejection Reason**: 優先順位や name の扱いといった共通の規則が各 Agent class に重複し、テストも難しくなる。
109
+
110
+ ### 配置時にその場で変換(中間成果物なし)
111
+
112
+ - **ALT-011**: **Description**: 変換結果をファイルに残さず、配置先へ直接書き込む。
113
+ - **ALT-012**: **Rejection Reason**: 変換結果を検査できず、ファイル名や配置先の誤りを追跡しにくい。
114
+
115
+ ## References
116
+
117
+ - **REF-001**: ADR-0002(extension と metadata DSL)、ADR-0003(artifact scope)、ADR-0004(外部 Agent と実行時の選択)
118
+ - **REF-002**: `README.md` 冒頭
@@ -0,0 +1,92 @@
1
+ ---
2
+ title: "ADR-0002: Source package モデルと metadata DSL"
3
+ status: "Accepted"
4
+ date: "2026-10-02"
5
+ authors: "T.Watanabe (maintainer)"
6
+ tags: ["architecture", "decision", "dsl", "metadata", "package"]
7
+ supersedes: ""
8
+ superseded_by: ""
9
+ ---
10
+
11
+ # ADR-0002: Source package モデルと metadata DSL
12
+
13
+ ## Status
14
+
15
+ Proposed | **Accepted** | Rejected | Superseded | Deprecated
16
+
17
+ ## Context
18
+
19
+ 作者は Agent 製品ごとの差異を意識せずに一つの source を書きたい。一方で、権限表現のように Agent ごとに表現が異なる metadata や、特定 Agent にしか書けない metadata、特定 Agent にしか配りたくない extension が存在する。
20
+
21
+ - skill と subagent を一つの機能として組み合わせて配布したい。
22
+ - entrypoint(`SKILL.md` や agent の `*.md`)は単体でも有効な文書であり、その frontmatter も尊重したい。
23
+
24
+ ## Decision
25
+
26
+ 本 ADR は ADR-0001 の PRI-001(single source)、PRI-003(Agent 固有の記述の置き場所)、PRI-004(本文は変換しない)を具体化する。
27
+
28
+ ### Package と extension
29
+
30
+ - **package** は `<source_root>/<package>/` にある作者単位のまとまり。
31
+ - **extension** は package 内の type 別要素で、`<package>/<type>/` 一つが一 extension。type は現在 `skill` と `agent`。
32
+
33
+ ADR-0001 の図で compile の入力となる extension は、次の構成を持つ。
34
+
35
+ ```text
36
+ <package>/<type>/
37
+ ├── <entrypoint>.md frontmatter + 本文(単体でも有効な文書)
38
+ ├── metadata.yaml 任意。compile の入力で、配布しない
39
+ └── その他 同梱ファイル。そのまま配布する
40
+ ```
41
+
42
+ - entrypoint は type が決める。skill は `SKILL.md`、agent は直下のただ一つの `*.md`(0 または 2 以上はエラー)。
43
+
44
+ ### Extension metadata DSL(`metadata.yaml`、任意)
45
+
46
+ | Key | 意味 |
47
+ |---|---|
48
+ | `name` | extension identity。配置名になる。 |
49
+ | `deploy_to` | 配布先 Agent 名の制約。省略時は構成済み全 Agent。 |
50
+ | `adaptive` | Agent が artifact 表現を決める source fragment。規則のない field はそのまま通る。 |
51
+ | `static.common` | 全 Agent に適応なしで書かれる fragment。 |
52
+ | `static.agents.<agent>` | 指定 Agent にのみ適応なしで書かれる fragment。 |
53
+
54
+ - `adaptive` は「動的」ではなく「表現の決定権が Agent 側にある」ことを宣言する。
55
+ - `deploy_to` は選択の制約であり section に属さず、artifact metadata にも現れない。互換性の宣言ではない。対象外の Agent には artifact を一切生成しない。
56
+
57
+ ### 優先順位(後勝ち)
58
+
59
+ - **Identity**: package ディレクトリ名 < entrypoint frontmatter `name` < `metadata.yaml` top-level `name`
60
+ - **Artifact metadata**: entrypoint frontmatter < `static.common` < Agent 適応済み fragment(`adaptive` 由来)< `static.agents.<agent>`
61
+
62
+ ## Consequences
63
+
64
+ ### Positive
65
+
66
+ - **POS-001**: 作者は一つの source で複数 Agent をカバーでき、Agent 固有の差は `adaptive` と `static.agents` に局所化される。
67
+ - **POS-002**: entrypoint 単体でも有効な文書のまま、`metadata.yaml` で上書き・補完できる。
68
+ - **POS-003**: `deploy_to` により未検証の Agent への配布を作者が制限できる。
69
+
70
+ ### Negative
71
+
72
+ - **NEG-001**: 優先順位が 4 段あり、最終 metadata の出所を追うには規則の理解が必要。
73
+ - **NEG-002**: `adaptive` の field 語彙(例: `permissions`)は Agent 側の翻訳規則に暗黙に依存し、DSL として明示的に固定されていない。
74
+ - **NEG-003**: `deploy_to` の未知の Agent 名は警告のみで無視されるため、typo が配布漏れとして見逃されうる。
75
+ - **NEG-004**: source 構造の不正(未対応 type、空 package など)を一括検出する仕組みはまだない。
76
+
77
+ ## Alternatives Considered
78
+
79
+ ### 未知の `deploy_to` 名を厳格にエラー
80
+
81
+ - **ALT-001**: **Description**: 構成済み Agent に存在しない名前を build エラーにする。
82
+ - **ALT-002**: **Rejection Reason**: 外部 Agent を読み込んだかどうかで source の妥当性が変わってしまう。source 検証が整備されるまでは警告に留める。
83
+
84
+ ### Agent ごとのファイル名をユーザー設定可能にする
85
+
86
+ - **ALT-003**: **Description**: artifact のファイル名を metadata で指定可能にする。
87
+ - **ALT-004**: **Rejection Reason**: ファイル名は Agent 製品の規約であり、作者が決めるものではない。
88
+
89
+ ## References
90
+
91
+ - **REF-001**: ADR-0001(翻訳規則)、ADR-0003(`deploy_to` と scope)
92
+ - **REF-002**: `README.md`「Extension metadata」
@@ -0,0 +1,67 @@
1
+ ---
2
+ title: "ADR-0003: Compile 時に決定する artifact scope(shared / own)"
3
+ status: "Accepted"
4
+ date: "2026-10-02"
5
+ authors: "T.Watanabe (maintainer)"
6
+ tags: ["architecture", "decision", "scope", "skill", "deploy"]
7
+ supersedes: ""
8
+ superseded_by: ""
9
+ ---
10
+
11
+ # ADR-0003: Compile 時に決定する artifact scope(shared / own)
12
+
13
+ ## Status
14
+
15
+ Proposed | **Accepted** | Rejected | Superseded | Deprecated
16
+
17
+ ## Context
18
+
19
+ 一部の Agent 製品は共通の skill ディレクトリ(`~/.agents/skills`)を読む。同一内容の skill をそこに一度だけ置けば重複を避けられるが、次の場合は共有できない。
20
+
21
+ - Agent 固有の適応で metadata が変わる skill を共有ディレクトリに置くと、他の Agent が誤った metadata を読む。
22
+ - `deploy_to` で配布先を限定した extension を共有ディレクトリに置くと、全 Agent に届いてしまい制限が無効になる。
23
+ - 共有 skill ディレクトリを読まない Agent(Claude Code)がある。
24
+ - agent(subagent)には共有の配置先がない。
25
+
26
+ ## Decision
27
+
28
+ 本 ADR は ADR-0001 の PRI-002(製品の知識は Agent class に閉じる)と PRI-006(判断は compile で完結する)を、配置先の分類に適用する。
29
+
30
+ 各 artifact を **`shared`** または **`own`** のいずれかに分類し、その判定を **compile 時に**行って compile 結果に記録する。
31
+
32
+ 判定規則(上から順に適用):
33
+
34
+ 1. extension が `deploy_to` を持つ → `own`
35
+ 2. Agent がその type の共有をサポートしない(agent type 全般、Claude Code の skill)→ `own`
36
+ 3. Agent 適応で metadata が変化した、または `static.agents.<agent>` が存在する → `own`
37
+ 4. それ以外 → `shared`
38
+
39
+ `static.common` は全 Agent に共通のため判定に影響しない。PRI-006 に従い、deploy は記録された scope をそのまま使う。
40
+
41
+ ## Consequences
42
+
43
+ ### Positive
44
+
45
+ - **POS-001**: 同一内容の skill を共有ディレクトリに一度だけ配置でき、Agent 間の重複を避けられる。
46
+ - **POS-002**: Agent 固有の内容が他の Agent へ漏れることを構造的に防ぐ。
47
+
48
+ ### Negative
49
+
50
+ - **NEG-001**: metadata の小さな差でも `own` に切り替わるため、作者が意図せず配置先が変わることがある。
51
+ - **NEG-002**: shared artifact は、実行時に対象の Agent を絞っても、共有ディレクトリ経由で他の Agent に届く。この到達範囲を制御する仕組みは未決定。
52
+
53
+ ## Alternatives Considered
54
+
55
+ ### 常に Agent 固有ディレクトリへ配置
56
+
57
+ - **ALT-001**: **Description**: 共有ディレクトリを使わず、すべて `own` にする。
58
+ - **ALT-002**: **Rejection Reason**: 共有ディレクトリを読む Agent 間で同一 skill が重複し、共通規約を活かせない。
59
+
60
+ ### 作者が scope を明示指定
61
+
62
+ - **ALT-003**: **Description**: `metadata.yaml` に `shared: true` のような指定を設ける。
63
+ - **ALT-004**: **Rejection Reason**: 内容が Agent 固有である場合に誤指定で漏洩しうる。内容から機械的に導出する方が安全。
64
+
65
+ ## References
66
+
67
+ - **REF-001**: ADR-0001、ADR-0002(`deploy_to`)