twagent 0.1.0__tar.gz

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 (36) hide show
  1. twagent-0.1.0/LICENSE +28 -0
  2. twagent-0.1.0/PKG-INFO +259 -0
  3. twagent-0.1.0/README.md +242 -0
  4. twagent-0.1.0/pyproject.toml +109 -0
  5. twagent-0.1.0/setup.cfg +4 -0
  6. twagent-0.1.0/src/twagent/__init__.py +1 -0
  7. twagent-0.1.0/src/twagent/cli.py +849 -0
  8. twagent-0.1.0/src/twagent/config.py +439 -0
  9. twagent-0.1.0/src/twagent/deploy.py +620 -0
  10. twagent-0.1.0/src/twagent/diff.py +198 -0
  11. twagent-0.1.0/src/twagent/doctor.py +109 -0
  12. twagent-0.1.0/src/twagent/extractor.py +135 -0
  13. twagent-0.1.0/src/twagent/interpolate.py +62 -0
  14. twagent-0.1.0/src/twagent/mcp.py +147 -0
  15. twagent-0.1.0/src/twagent/selector.py +191 -0
  16. twagent-0.1.0/src/twagent.egg-info/PKG-INFO +259 -0
  17. twagent-0.1.0/src/twagent.egg-info/SOURCES.txt +34 -0
  18. twagent-0.1.0/src/twagent.egg-info/dependency_links.txt +1 -0
  19. twagent-0.1.0/src/twagent.egg-info/entry_points.txt +2 -0
  20. twagent-0.1.0/src/twagent.egg-info/requires.txt +4 -0
  21. twagent-0.1.0/src/twagent.egg-info/top_level.txt +1 -0
  22. twagent-0.1.0/tests/test_cli.py +12 -0
  23. twagent-0.1.0/tests/test_cli_apply.py +400 -0
  24. twagent-0.1.0/tests/test_cli_diff.py +68 -0
  25. twagent-0.1.0/tests/test_cli_doctor.py +57 -0
  26. twagent-0.1.0/tests/test_cli_extract.py +41 -0
  27. twagent-0.1.0/tests/test_cli_listings.py +97 -0
  28. twagent-0.1.0/tests/test_config.py +454 -0
  29. twagent-0.1.0/tests/test_deploy_render.py +67 -0
  30. twagent-0.1.0/tests/test_deploy_symlinks.py +80 -0
  31. twagent-0.1.0/tests/test_doctor.py +108 -0
  32. twagent-0.1.0/tests/test_extractor.py +118 -0
  33. twagent-0.1.0/tests/test_interpolate.py +106 -0
  34. twagent-0.1.0/tests/test_mcp.py +160 -0
  35. twagent-0.1.0/tests/test_performance.py +88 -0
  36. twagent-0.1.0/tests/test_selector.py +157 -0
twagent-0.1.0/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, sysid
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
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
twagent-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,259 @@
1
+ Metadata-Version: 2.4
2
+ Name: twagent
3
+ Version: 0.1.0
4
+ Summary: twagent CLI
5
+ Author-email: sysid <sysid@gmx.de>
6
+ License-Expression: BSD-3-Clause
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Programming Language :: Python :: 3
9
+ Requires-Python: >=3.13
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: typer>=0.15
13
+ Requires-Dist: jinja2>=3.1
14
+ Requires-Dist: simple-term-menu>=1.6
15
+ Requires-Dist: rich>=13.0
16
+ Dynamic: license-file
17
+
18
+ <p align="left">
19
+ <img src="doc/twagent-logo.png" alt="twagent logo" width="300">
20
+ </p>
21
+
22
+ Unified configuration framework for AI coding agents — Claude Code, Copilot CLI,
23
+ and Pi today; extensible to others. **One canonical TOML, one CLI, two deploy
24
+ modes.**
25
+
26
+ Replaces and supersedes two earlier tools:
27
+ - `twmcp` (MCP servers only, multiple agents)
28
+ - `devops-binx/agent/render.py` (instructions + skills, multiple agents)
29
+
30
+ ## What it does
31
+
32
+ You edit a single canonical TOML at `~/.config/twagent/config.toml` describing
33
+ every artifact you care about — instruction templates, skills, subagents,
34
+ prompts, MCP servers — plus the agents that consume them and the profiles
35
+ that bundle them. Then:
36
+
37
+ ```sh
38
+ twagent apply # global sync
39
+ twagent apply --here --select tw-claude # ad-hoc local deploy
40
+ twagent apply -s e2e-emea -a copilot-cli # swap MCP env for one agent
41
+ ```
42
+
43
+ twagent renders per-agent instruction files (Jinja2), symlinks file artifacts
44
+ into the right per-agent directories, and compiles MCP server configuration
45
+ into each agent's expected JSON shape.
46
+
47
+ ## Mental model
48
+
49
+ ```
50
+ ┌──────────────┐ ┌─────────────┐
51
+ │ Registries │ → │ Profiles │ → apply (--global | --here)
52
+ │ │ │ (composable│ │
53
+ │ instructions │ │ bundles) │ ▼
54
+ │ skills │ │ │ per-agent paths
55
+ │ subagents │ │ extends... │ (global or cwd-relative)
56
+ │ prompts │ │ │
57
+ │ servers │ │ │
58
+ └──────────────┘ └─────────────┘
59
+ ```
60
+
61
+ - **Artifacts** live in registries: each one has a `name` + `source` path.
62
+ - **Profiles** bundle artifacts (skills, subagents, prompts, instructions,
63
+ servers) and compose via `extends`.
64
+ - **Agents** declare which capabilities they support and where their files go.
65
+ Each agent has an optional `global_profile` — what bare `apply` deploys.
66
+ - **`--select`** is polymorphic: it accepts profile names AND artifact names,
67
+ mixed. It's exhaustive — only the kinds derivable from the selection deploy.
68
+
69
+ ## Quickstart
70
+
71
+ ```sh
72
+ twagent edit --init # creates a stub at ~/.config/twagent/config.toml
73
+
74
+ # Migrate existing per-agent MCP into the canonical TOML (stdout-only)
75
+ twagent extract ~/.claude.json >> ~/.config/twagent/config.toml
76
+
77
+ # Inspect
78
+ twagent agents # capabilities + global_profile + paths
79
+ twagent profiles # extends-expanded contents per profile
80
+ twagent status # per-agent global deployment view
81
+
82
+ # Preview, then deploy
83
+ twagent apply -n # dry-run, secrets masked
84
+ twagent apply # do it
85
+
86
+ # Maintenance
87
+ twagent diff # what diverges from config?
88
+ twagent doctor # dangling links / missing sources
89
+ ```
90
+
91
+ ## `apply` — non-trivial examples
92
+
93
+ The deploy command is the surface area. Two modes:
94
+
95
+ | Mode | Default | What it writes |
96
+ |---|---|---|
97
+ | `--global` (default, `-G`) | yes | Each agent's `global_profile`, to canonical paths (`~/.claude/...`, `~/.copilot/...`, `~/.pi/...`) |
98
+ | `--here` (`-H`) | no | A CLI-supplied selection, into the **current directory** via each agent's `paths.project.*` |
99
+
100
+ ### Inspect first, deploy second
101
+
102
+ ```sh
103
+ twagent apply -n # full preview, masked secrets
104
+ twagent apply -n -S # same, secrets revealed
105
+ twagent apply -n -a claude-code # preview ONE agent
106
+ twagent apply -n -a claude-code -a copilot-cli # preview a subset (repeatable)
107
+ ```
108
+
109
+ ### Override the default profile, globally
110
+
111
+ When you want to swap your MCP environment "for the day" without editing
112
+ config:
113
+
114
+ ```sh
115
+ twagent apply -s e2e-emea # swap globally (all 3 agents
116
+ # with mcp capability)
117
+ twagent apply -s e2e-emea -a copilot-cli # only copilot's MCP file
118
+ # NOTHING ELSE rewritten —
119
+ # no instruction render,
120
+ # no skill symlinks
121
+ twagent apply -s e2e-emea,bkmr-memory # mix: e2e MCP set + one skill
122
+ ```
123
+
124
+ `--select` is **exhaustive**: kinds that aren't in the selection are not
125
+ touched. This is why `-s e2e-emea` (servers-only) doesn't render CLAUDE.md.
126
+
127
+ ### Mixed profile + artifact selection
128
+
129
+ ```sh
130
+ twagent apply -s tw-claude # the tw-claude profile in full
131
+ twagent apply -s tw-claude,tw-cucumber-to-http # profile + an extra one-off
132
+ # skill — dedup'd, profile
133
+ # contents win on collision
134
+ twagent apply -s core,pr_review,e2e-us # three profiles composed
135
+ # at the CLI level (no need
136
+ # to define a wrapper profile)
137
+ ```
138
+
139
+ ### Project-local deploys with `--here`
140
+
141
+ ```sh
142
+ cd ~/dev/los/los-cha
143
+
144
+ twagent apply -H -s tw-claude,tw-cucumber-to-http -a claude-code
145
+ twagent apply -H -s tw-copilot,tw-cucumber-to-http -a copilot-cli
146
+
147
+ # Faster: just the project-specific delta
148
+ twagent apply -H -s tw-cucumber-to-http -a claude-code
149
+ ```
150
+
151
+ `--here` writes under cwd via each agent's `paths.project.*`. Subdirs are
152
+ created if missing — this is an explicit user act.
153
+
154
+ ### Just the instruction templates
155
+
156
+ In v3 instructions are first-class artifacts. Render only the templates:
157
+
158
+ ```sh
159
+ twagent apply -s AGENT-md # render the AGENT-md template
160
+ # to every agent's instruction
161
+ # path — nothing else
162
+ twagent apply -s AGENT-md -a claude-code # one agent's instructions only
163
+ ```
164
+
165
+ ### Interactive picker
166
+
167
+ ```sh
168
+ twagent apply -i # pick from a TUI menu
169
+ # of all profiles + artifacts
170
+ twagent apply -s tw-claude -i # picker pre-checked with
171
+ # tw-claude's contents — add
172
+ # or remove from there
173
+ ```
174
+
175
+ `-i` cancellation (Esc) exits without deploying.
176
+
177
+ ### Day-to-day flow
178
+
179
+ ```sh
180
+ $EDITOR ~/.config/twagent/config.toml # tweak something
181
+ twagent diff # what would change?
182
+ twagent apply # do it
183
+ ```
184
+
185
+ ## `apply` flags
186
+
187
+ | Long | Short | Effect |
188
+ |---|---|---|
189
+ | `--global` | `-G` | Default mode. Deploy each agent's `global_profile` to canonical paths. |
190
+ | `--here` | `-H` | Deploy `--select` set into current directory via `paths.project.*`. |
191
+ | `--agent <id>` | `-a` | Repeatable. Restrict to specific agents. |
192
+ | `--select <names>` | `-s` | csv of profile names AND/OR artifact names. `none` deploys empty. |
193
+ | `--interactive` | `-i` | Open TUI picker. `--select`, if also given, pre-checks items. |
194
+ | `--dry-run` | `-n` | Show plan, write nothing. Secrets masked unless `--show-secrets`. |
195
+ | `--show-secrets` | `-S` | Reveal `${VAR}`-resolved values in dry-run / diff output. |
196
+
197
+ ## All commands
198
+
199
+ | Command | Purpose |
200
+ |---|---|
201
+ | `apply` | Deploy resolved configuration to disk. |
202
+ | `diff` | Show pending changes between config and on-disk state. Read-only. |
203
+ | `status` | Per-agent global deployment view (capabilities + `global_profile`). |
204
+ | `agents` | List agents with resolved paths and capabilities (`-j` for JSON). |
205
+ | `profiles` | List profiles with their `extends`-expanded contents. |
206
+ | `doctor` | Health check: dangling symlinks, missing sources, capability mismatches. |
207
+ | `extract <mcp.json>` | Convert an existing per-agent MCP file to canonical TOML on stdout. |
208
+ | `edit` | Open the canonical config in `$EDITOR`. `--init` creates a stub. `-t <name>` opens an instruction template. |
209
+ | `version` | Print the installed version. |
210
+
211
+ ### Global flags
212
+
213
+ `--config <path>` (`-c`) — alternate config location.
214
+ `--verbose` (`-v`) — debug logging via `RichHandler` to stderr.
215
+
216
+ ## Design
217
+
218
+ Headlines (v3 schema):
219
+
220
+ - **One canonical TOML.** Per-agent paths, vars, MCP-format selection,
221
+ and `global_profile` all live in the same file.
222
+ - **Five artifact registries**: `instructions`, `skills`, `subagents`,
223
+ `prompts`, `servers`. All names are globally unique (shadow rule).
224
+ - **Profiles bundle artifact references** by kind, and compose via `extends`
225
+ (depth-first, parent-first, dedup'd per kind, first-occurrence wins).
226
+ - **No `[[scopes]]` blocks.** Global deployment is per-agent
227
+ (`global_profile`); local deployment is ad-hoc CLI (`apply --here --select`).
228
+ - **Symlinks for file artifacts** (skills/subagents/prompts).
229
+ - **Render for instructions** (Jinja2, `StrictUndefined`).
230
+ - **Compile for MCP** (per-format translator handles agent-specific quirks).
231
+ - **Two-layer Jinja vars:** `[common.vars]` overlaid by `[agents.<id>.vars]`.
232
+ - **`${VAR:-default}` interpolation** inside MCP `env` and `headers` only.
233
+ - **Secrets masked in dry-run / diff output by default.** Opt in with
234
+ `--show-secrets`.
235
+ - **`--select` is exhaustive.** Deploys ONLY the capability kinds the
236
+ selection touches. Bare `apply` (no `--select`) deploys everything in
237
+ the agent's `global_profile`.
238
+
239
+ ## Install
240
+
241
+ ```bash
242
+ make install
243
+ ```
244
+
245
+ ## Develop
246
+
247
+ ```bash
248
+ uv sync
249
+ make test
250
+ make format
251
+ make lint
252
+ make build
253
+ ```
254
+
255
+ Python 3.13+. `uv` for everything else.
256
+
257
+ ## License
258
+
259
+ BSD-3-Clause.
@@ -0,0 +1,242 @@
1
+ <p align="left">
2
+ <img src="doc/twagent-logo.png" alt="twagent logo" width="300">
3
+ </p>
4
+
5
+ Unified configuration framework for AI coding agents — Claude Code, Copilot CLI,
6
+ and Pi today; extensible to others. **One canonical TOML, one CLI, two deploy
7
+ modes.**
8
+
9
+ Replaces and supersedes two earlier tools:
10
+ - `twmcp` (MCP servers only, multiple agents)
11
+ - `devops-binx/agent/render.py` (instructions + skills, multiple agents)
12
+
13
+ ## What it does
14
+
15
+ You edit a single canonical TOML at `~/.config/twagent/config.toml` describing
16
+ every artifact you care about — instruction templates, skills, subagents,
17
+ prompts, MCP servers — plus the agents that consume them and the profiles
18
+ that bundle them. Then:
19
+
20
+ ```sh
21
+ twagent apply # global sync
22
+ twagent apply --here --select tw-claude # ad-hoc local deploy
23
+ twagent apply -s e2e-emea -a copilot-cli # swap MCP env for one agent
24
+ ```
25
+
26
+ twagent renders per-agent instruction files (Jinja2), symlinks file artifacts
27
+ into the right per-agent directories, and compiles MCP server configuration
28
+ into each agent's expected JSON shape.
29
+
30
+ ## Mental model
31
+
32
+ ```
33
+ ┌──────────────┐ ┌─────────────┐
34
+ │ Registries │ → │ Profiles │ → apply (--global | --here)
35
+ │ │ │ (composable│ │
36
+ │ instructions │ │ bundles) │ ▼
37
+ │ skills │ │ │ per-agent paths
38
+ │ subagents │ │ extends... │ (global or cwd-relative)
39
+ │ prompts │ │ │
40
+ │ servers │ │ │
41
+ └──────────────┘ └─────────────┘
42
+ ```
43
+
44
+ - **Artifacts** live in registries: each one has a `name` + `source` path.
45
+ - **Profiles** bundle artifacts (skills, subagents, prompts, instructions,
46
+ servers) and compose via `extends`.
47
+ - **Agents** declare which capabilities they support and where their files go.
48
+ Each agent has an optional `global_profile` — what bare `apply` deploys.
49
+ - **`--select`** is polymorphic: it accepts profile names AND artifact names,
50
+ mixed. It's exhaustive — only the kinds derivable from the selection deploy.
51
+
52
+ ## Quickstart
53
+
54
+ ```sh
55
+ twagent edit --init # creates a stub at ~/.config/twagent/config.toml
56
+
57
+ # Migrate existing per-agent MCP into the canonical TOML (stdout-only)
58
+ twagent extract ~/.claude.json >> ~/.config/twagent/config.toml
59
+
60
+ # Inspect
61
+ twagent agents # capabilities + global_profile + paths
62
+ twagent profiles # extends-expanded contents per profile
63
+ twagent status # per-agent global deployment view
64
+
65
+ # Preview, then deploy
66
+ twagent apply -n # dry-run, secrets masked
67
+ twagent apply # do it
68
+
69
+ # Maintenance
70
+ twagent diff # what diverges from config?
71
+ twagent doctor # dangling links / missing sources
72
+ ```
73
+
74
+ ## `apply` — non-trivial examples
75
+
76
+ The deploy command is the surface area. Two modes:
77
+
78
+ | Mode | Default | What it writes |
79
+ |---|---|---|
80
+ | `--global` (default, `-G`) | yes | Each agent's `global_profile`, to canonical paths (`~/.claude/...`, `~/.copilot/...`, `~/.pi/...`) |
81
+ | `--here` (`-H`) | no | A CLI-supplied selection, into the **current directory** via each agent's `paths.project.*` |
82
+
83
+ ### Inspect first, deploy second
84
+
85
+ ```sh
86
+ twagent apply -n # full preview, masked secrets
87
+ twagent apply -n -S # same, secrets revealed
88
+ twagent apply -n -a claude-code # preview ONE agent
89
+ twagent apply -n -a claude-code -a copilot-cli # preview a subset (repeatable)
90
+ ```
91
+
92
+ ### Override the default profile, globally
93
+
94
+ When you want to swap your MCP environment "for the day" without editing
95
+ config:
96
+
97
+ ```sh
98
+ twagent apply -s e2e-emea # swap globally (all 3 agents
99
+ # with mcp capability)
100
+ twagent apply -s e2e-emea -a copilot-cli # only copilot's MCP file
101
+ # NOTHING ELSE rewritten —
102
+ # no instruction render,
103
+ # no skill symlinks
104
+ twagent apply -s e2e-emea,bkmr-memory # mix: e2e MCP set + one skill
105
+ ```
106
+
107
+ `--select` is **exhaustive**: kinds that aren't in the selection are not
108
+ touched. This is why `-s e2e-emea` (servers-only) doesn't render CLAUDE.md.
109
+
110
+ ### Mixed profile + artifact selection
111
+
112
+ ```sh
113
+ twagent apply -s tw-claude # the tw-claude profile in full
114
+ twagent apply -s tw-claude,tw-cucumber-to-http # profile + an extra one-off
115
+ # skill — dedup'd, profile
116
+ # contents win on collision
117
+ twagent apply -s core,pr_review,e2e-us # three profiles composed
118
+ # at the CLI level (no need
119
+ # to define a wrapper profile)
120
+ ```
121
+
122
+ ### Project-local deploys with `--here`
123
+
124
+ ```sh
125
+ cd ~/dev/los/los-cha
126
+
127
+ twagent apply -H -s tw-claude,tw-cucumber-to-http -a claude-code
128
+ twagent apply -H -s tw-copilot,tw-cucumber-to-http -a copilot-cli
129
+
130
+ # Faster: just the project-specific delta
131
+ twagent apply -H -s tw-cucumber-to-http -a claude-code
132
+ ```
133
+
134
+ `--here` writes under cwd via each agent's `paths.project.*`. Subdirs are
135
+ created if missing — this is an explicit user act.
136
+
137
+ ### Just the instruction templates
138
+
139
+ In v3 instructions are first-class artifacts. Render only the templates:
140
+
141
+ ```sh
142
+ twagent apply -s AGENT-md # render the AGENT-md template
143
+ # to every agent's instruction
144
+ # path — nothing else
145
+ twagent apply -s AGENT-md -a claude-code # one agent's instructions only
146
+ ```
147
+
148
+ ### Interactive picker
149
+
150
+ ```sh
151
+ twagent apply -i # pick from a TUI menu
152
+ # of all profiles + artifacts
153
+ twagent apply -s tw-claude -i # picker pre-checked with
154
+ # tw-claude's contents — add
155
+ # or remove from there
156
+ ```
157
+
158
+ `-i` cancellation (Esc) exits without deploying.
159
+
160
+ ### Day-to-day flow
161
+
162
+ ```sh
163
+ $EDITOR ~/.config/twagent/config.toml # tweak something
164
+ twagent diff # what would change?
165
+ twagent apply # do it
166
+ ```
167
+
168
+ ## `apply` flags
169
+
170
+ | Long | Short | Effect |
171
+ |---|---|---|
172
+ | `--global` | `-G` | Default mode. Deploy each agent's `global_profile` to canonical paths. |
173
+ | `--here` | `-H` | Deploy `--select` set into current directory via `paths.project.*`. |
174
+ | `--agent <id>` | `-a` | Repeatable. Restrict to specific agents. |
175
+ | `--select <names>` | `-s` | csv of profile names AND/OR artifact names. `none` deploys empty. |
176
+ | `--interactive` | `-i` | Open TUI picker. `--select`, if also given, pre-checks items. |
177
+ | `--dry-run` | `-n` | Show plan, write nothing. Secrets masked unless `--show-secrets`. |
178
+ | `--show-secrets` | `-S` | Reveal `${VAR}`-resolved values in dry-run / diff output. |
179
+
180
+ ## All commands
181
+
182
+ | Command | Purpose |
183
+ |---|---|
184
+ | `apply` | Deploy resolved configuration to disk. |
185
+ | `diff` | Show pending changes between config and on-disk state. Read-only. |
186
+ | `status` | Per-agent global deployment view (capabilities + `global_profile`). |
187
+ | `agents` | List agents with resolved paths and capabilities (`-j` for JSON). |
188
+ | `profiles` | List profiles with their `extends`-expanded contents. |
189
+ | `doctor` | Health check: dangling symlinks, missing sources, capability mismatches. |
190
+ | `extract <mcp.json>` | Convert an existing per-agent MCP file to canonical TOML on stdout. |
191
+ | `edit` | Open the canonical config in `$EDITOR`. `--init` creates a stub. `-t <name>` opens an instruction template. |
192
+ | `version` | Print the installed version. |
193
+
194
+ ### Global flags
195
+
196
+ `--config <path>` (`-c`) — alternate config location.
197
+ `--verbose` (`-v`) — debug logging via `RichHandler` to stderr.
198
+
199
+ ## Design
200
+
201
+ Headlines (v3 schema):
202
+
203
+ - **One canonical TOML.** Per-agent paths, vars, MCP-format selection,
204
+ and `global_profile` all live in the same file.
205
+ - **Five artifact registries**: `instructions`, `skills`, `subagents`,
206
+ `prompts`, `servers`. All names are globally unique (shadow rule).
207
+ - **Profiles bundle artifact references** by kind, and compose via `extends`
208
+ (depth-first, parent-first, dedup'd per kind, first-occurrence wins).
209
+ - **No `[[scopes]]` blocks.** Global deployment is per-agent
210
+ (`global_profile`); local deployment is ad-hoc CLI (`apply --here --select`).
211
+ - **Symlinks for file artifacts** (skills/subagents/prompts).
212
+ - **Render for instructions** (Jinja2, `StrictUndefined`).
213
+ - **Compile for MCP** (per-format translator handles agent-specific quirks).
214
+ - **Two-layer Jinja vars:** `[common.vars]` overlaid by `[agents.<id>.vars]`.
215
+ - **`${VAR:-default}` interpolation** inside MCP `env` and `headers` only.
216
+ - **Secrets masked in dry-run / diff output by default.** Opt in with
217
+ `--show-secrets`.
218
+ - **`--select` is exhaustive.** Deploys ONLY the capability kinds the
219
+ selection touches. Bare `apply` (no `--select`) deploys everything in
220
+ the agent's `global_profile`.
221
+
222
+ ## Install
223
+
224
+ ```bash
225
+ make install
226
+ ```
227
+
228
+ ## Develop
229
+
230
+ ```bash
231
+ uv sync
232
+ make test
233
+ make format
234
+ make lint
235
+ make build
236
+ ```
237
+
238
+ Python 3.13+. `uv` for everything else.
239
+
240
+ ## License
241
+
242
+ BSD-3-Clause.
@@ -0,0 +1,109 @@
1
+ [project]
2
+ name = "twagent"
3
+ version = "0.1.0"
4
+ description = "twagent CLI"
5
+ readme = "README.md"
6
+ license = "BSD-3-Clause"
7
+ authors = [
8
+ { name = "sysid", email = "sysid@gmx.de" },
9
+ ]
10
+ requires-python = ">=3.13"
11
+ classifiers = [
12
+ "Development Status :: 3 - Alpha",
13
+ "Programming Language :: Python :: 3",
14
+ ]
15
+ dependencies = [
16
+ "typer>=0.15",
17
+ "jinja2>=3.1",
18
+ "simple-term-menu>=1.6",
19
+ "rich>=13.0",
20
+ ]
21
+
22
+ [project.scripts]
23
+ twagent = "twagent.cli:app"
24
+
25
+ [dependency-groups]
26
+ dev = [
27
+ "pytest>=8.3.4",
28
+ "pytest-cov>=6.0.0",
29
+ "ruff>=0.8.4",
30
+ "pre-commit>=4.0.0",
31
+ "bump-my-version>=0.28.0",
32
+ "build>=1.2.2",
33
+ ]
34
+
35
+ [build-system]
36
+ requires = ["setuptools>=61"]
37
+ build-backend = "setuptools.build_meta"
38
+
39
+ [tool.setuptools.packages.find]
40
+ where = ["src"]
41
+ include = ["twagent*"]
42
+
43
+ [tool.pytest.ini_options]
44
+ markers = [
45
+ "integration: marks tests as integration tests",
46
+ "experimentation: marks tests as experimental tests, not to be run in CICD",
47
+ ]
48
+
49
+ [tool.coverage.run]
50
+ source = ["twagent"]
51
+ omit = [
52
+ "tests/*",
53
+ "**/__main__.py",
54
+ "**/.venv/*",
55
+ "**/site-packages/*",
56
+ ]
57
+ branch = true
58
+
59
+ [tool.coverage.report]
60
+ show_missing = true
61
+ skip_covered = true
62
+ fail_under = 85
63
+
64
+ [tool.ruff]
65
+ line-length = 88
66
+ indent-width = 4
67
+ target-version = "py313"
68
+ exclude = [
69
+ ".direnv", ".eggs", ".git", ".mypy_cache", ".pytest_cache",
70
+ ".ruff_cache", ".venv", "__pypackages__", "build", "dist",
71
+ "node_modules", "site-packages", "venv",
72
+ ]
73
+
74
+ [tool.ruff.lint]
75
+ select = ["E4", "E7", "E9", "F"]
76
+ fixable = ["ALL"]
77
+
78
+ [tool.ruff.format]
79
+ quote-style = "double"
80
+ indent-style = "space"
81
+ skip-magic-trailing-comma = false
82
+ line-ending = "auto"
83
+
84
+ [tool.bumpversion]
85
+ current_version = "0.1.0"
86
+ commit = true
87
+ tag = false
88
+ tag_name = "v{new_version}"
89
+ message = "Bump version to {new_version}"
90
+
91
+ [tool.bumpversion.file_patterns]
92
+ "src/twagent/__init__.py" = [
93
+ {search = "__version__ = '{current_version}'", replace = "__version__ = '{new_version}'"},
94
+ ]
95
+ "VERSION" = [
96
+ {search = "{current_version}", replace = "{new_version}"},
97
+ ]
98
+ "pyproject.toml" = [
99
+ {search = "version = {current_version}", replace = "version = {new_version}"},
100
+ ]
101
+
102
+ [[tool.bumpversion.files]]
103
+ filename = "VERSION"
104
+
105
+ [[tool.bumpversion.files]]
106
+ filename = "pyproject.toml"
107
+
108
+ [[tool.bumpversion.files]]
109
+ filename = "src/twagent/__init__.py"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"