agentharnesses-cli 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentharnesses-cli
3
+ Version: 0.1.0
4
+ Summary: CLI tools for agentharnesses.io
5
+ Project-URL: Homepage, https://agentharnesses.io
6
+ Project-URL: Repository, https://github.com/agentharnesses/cli
7
+ License-Expression: Apache-2.0
8
+ Requires-Python: >=3.10
9
+ Requires-Dist: click>=8.1
10
+ Description-Content-Type: text/markdown
11
+
12
+ # agentharnesses-cli
13
+
14
+ Command line tools for [agentharnesses.io](http://agentharnesses.io).
15
+
16
+ ## Installation
17
+
18
+ ### From PyPI (once published)
19
+
20
+ ```bash
21
+ pip install agentharnesses-cli
22
+ ```
23
+
24
+ ### From source
25
+
26
+ ```bash
27
+ git clone https://github.com/your-org/cli.git
28
+ cd cli
29
+ pip install .
30
+ ```
31
+
32
+ ### Development install
33
+
34
+ ```bash
35
+ git clone https://github.com/your-org/cli.git
36
+ cd cli
37
+ pip install -e .
38
+ ```
39
+
40
+ The `-e` flag installs in editable mode so changes to the source are reflected immediately without reinstalling.
41
+
42
+ ## Usage
43
+
44
+ ```bash
45
+ ahar --help
46
+ ```
47
+
48
+ ### `ahar init`
49
+
50
+ Initialize a new harness in the current directory:
51
+
52
+ ```bash
53
+ ahar init
54
+ ```
55
+
56
+ Optionally specify a name (defaults to the directory name):
57
+
58
+ ```bash
59
+ ahar init my-harness
60
+ ```
61
+
62
+ This creates a `harness.yaml` file in the current directory.
@@ -0,0 +1,8 @@
1
+ ahar/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ ahar/main.py,sha256=tqloJWAyOIJ4WpuudghCiMazC3qI0VPk33262TZZIDU,160
3
+ ahar/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ ahar/commands/init.py,sha256=-2mkAzPDpLwRz2hj9pyk5MegSA7RL39jw94G74Vf_KI,5455
5
+ agentharnesses_cli-0.1.0.dist-info/METADATA,sha256=bvLjcwk2p-CB_mkvBA7t4H791b6P1MeUrLYVcc6SJwo,1125
6
+ agentharnesses_cli-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
7
+ agentharnesses_cli-0.1.0.dist-info/entry_points.txt,sha256=ILVBX997IkyOrGaIz5t2ICDdJsOwYHwu2cphSB0XtFc,39
8
+ agentharnesses_cli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ahar = ahar.main:cli
ahar/__init__.py ADDED
File without changes
File without changes
ahar/commands/init.py ADDED
@@ -0,0 +1,200 @@
1
+ import os
2
+ import subprocess
3
+ import sys
4
+ import click
5
+
6
+ _METASKILL_REPO = "https://github.com/agentharnesses/metaskill" # TODO: replace with final URL
7
+ _METASKILL_DEST = ".claude/plugins/metaskill"
8
+ _MAINTAIN_SKILL_DEST = ".claude/skills/maintain-harness.md"
9
+
10
+ _MAINTAIN_SKILL = """\
11
+ ---
12
+ name: maintain-harness
13
+ description: How to maintain and update this harness — updating HARNESS.md, adding skills and references, managing the skill index.
14
+ ---
15
+
16
+ ## Maintaining the Harness
17
+
18
+ When asked to maintain, update, or extend this harness, follow these conventions:
19
+
20
+ ### HARNESS.md
21
+ - Keep the `## Skills` section in sync with entries in `skills/SKILLS.md`
22
+ - Keep the `## References` section in sync with entries in `references/REFERENCES.md`
23
+ - Update the `description` frontmatter field when the harness scope changes
24
+
25
+ ### Adding a skill bucket
26
+ 1. Create `skills/<bucket-name>/<bucket-name>.md` with a frontmatter `name` and `description`
27
+ 2. Add an entry to `skills/SKILLS.md` summarizing when to use the bucket
28
+ 3. Add a bullet to the `## Skills` section in `HARNESS.md`
29
+
30
+ ### Adding a reference document
31
+ 1. Add the document to `references/`
32
+ 2. Add an entry to `references/REFERENCES.md` describing the document's purpose
33
+ 3. Add a bullet to the `## References` section in `HARNESS.md`
34
+
35
+ ### General conventions
36
+ - Keep skill descriptions actionable: "Use when..." not "This skill..."
37
+ - Reference documents should be stable facts; skill buckets contain executable guidance
38
+ - Prefer updating existing skill buckets over creating new ones when scope overlaps
39
+ """
40
+
41
+
42
+ def _write(path, content):
43
+ os.makedirs(os.path.dirname(path), exist_ok=True)
44
+ with open(path, "w") as f:
45
+ f.write(content)
46
+
47
+
48
+ def scaffold(root, name):
49
+ _write(
50
+ f"{root}/HARNESS.md",
51
+ f"""\
52
+ ---
53
+ name: {name}
54
+ description: TODO: describe what this harness does and the role it gives Claude.
55
+ ---
56
+
57
+ ## Upon loading the Harness
58
+
59
+ TODO: write the entry message Claude should internalize when this harness loads.
60
+
61
+ ## Skills
62
+
63
+ TODO: list skill buckets here as they are created.
64
+ - See `skills/SKILLS.md` for the full index.
65
+
66
+ ## References
67
+
68
+ TODO: list reference documents here as they are added.
69
+ - See `references/REFERENCES.md` for the full index.
70
+ """,
71
+ )
72
+
73
+ _write(
74
+ f"{root}/README.md",
75
+ f"""\
76
+ # {name}
77
+
78
+ TODO: brief description of this harness.
79
+ """,
80
+ )
81
+
82
+ _write(
83
+ f"{root}/.claude/settings.json",
84
+ f"""\
85
+ {{
86
+ "extraKnownMarketplaces": {{
87
+ "{name}": {{
88
+ "source": {{
89
+ "source": "directory",
90
+ "path": "{root}"
91
+ }}
92
+ }}
93
+ }},
94
+ "enabledPlugins": {{
95
+ "{name}@{name}": true
96
+ }}
97
+ }}
98
+ """,
99
+ )
100
+
101
+ _write(
102
+ f"{root}/skills/SKILLS.md",
103
+ """\
104
+ ---
105
+ description: TODO: describe the skill buckets in this harness and when to use each.
106
+ ---
107
+
108
+ TODO: add skill buckets here as they are created.
109
+ """,
110
+ )
111
+
112
+ _write(
113
+ f"{root}/references/REFERENCES.md",
114
+ """\
115
+ ---
116
+ description: TODO: describe the reference documents in this harness and how to use them.
117
+ ---
118
+
119
+ TODO: add reference documents here as they are added.
120
+ """,
121
+ )
122
+
123
+
124
+ _PRESETS = {
125
+ "claude": "Full Claude Code setup: metaskill plugin + maintain-harness skill",
126
+ "empty": "Bare minimum: no additional plugins or skills",
127
+ }
128
+
129
+
130
+ @click.command()
131
+ @click.argument("name", default=None, required=False)
132
+ def init(name):
133
+ """Initialize a new harness in the current directory."""
134
+ cwd = os.getcwd()
135
+
136
+ if name is None:
137
+ name = os.path.basename(cwd)
138
+
139
+ if os.path.exists(os.path.join(cwd, "HARNESS.md")):
140
+ click.echo("HARNESS.md already exists here — already initialized.", err=True)
141
+ sys.exit(1)
142
+
143
+ scaffold(cwd, name)
144
+
145
+ click.echo(f"Initialized harness '{name}' in {cwd}")
146
+ click.echo(" HARNESS.md")
147
+ click.echo(" README.md")
148
+ click.echo(" .claude/settings.json")
149
+ click.echo(" skills/SKILLS.md")
150
+ click.echo(" references/REFERENCES.md")
151
+
152
+ click.echo("\nClaude Code preset:")
153
+ for key, desc in _PRESETS.items():
154
+ click.echo(f" {key:<8} {desc}")
155
+
156
+ preset = click.prompt(
157
+ "Preset",
158
+ type=click.Choice(list(_PRESETS.keys()), case_sensitive=False),
159
+ default="claude",
160
+ show_choices=False,
161
+ )
162
+ _configure_claude(cwd, preset)
163
+
164
+
165
+ def _configure_claude(root, preset):
166
+ if preset == "empty":
167
+ click.echo("Skipping Claude Code plugin configuration (empty preset).")
168
+ return
169
+
170
+ # claude preset: metaskill + maintain-harness skill
171
+ _install_metaskill(root)
172
+ _install_maintain_skill(root)
173
+
174
+
175
+ def _install_metaskill(root):
176
+ dest = os.path.join(root, _METASKILL_DEST)
177
+ if os.path.exists(dest):
178
+ click.echo(f"Metaskill already present at {_METASKILL_DEST} — skipping clone.")
179
+ return
180
+
181
+ os.makedirs(os.path.dirname(dest), exist_ok=True)
182
+ click.echo(f"Cloning metaskill into {_METASKILL_DEST}...")
183
+ result = subprocess.run(
184
+ ["git", "clone", _METASKILL_REPO, dest],
185
+ capture_output=True,
186
+ text=True,
187
+ )
188
+ if result.returncode != 0:
189
+ click.echo(f"Clone failed:\n{result.stderr.strip()}", err=True)
190
+ sys.exit(1)
191
+ click.echo(f" {_METASKILL_DEST}")
192
+
193
+
194
+ def _install_maintain_skill(root):
195
+ dest = os.path.join(root, _MAINTAIN_SKILL_DEST)
196
+ if os.path.exists(dest):
197
+ click.echo(f"maintain-harness skill already present at {_MAINTAIN_SKILL_DEST} — skipping.")
198
+ return
199
+ _write(dest, _MAINTAIN_SKILL)
200
+ click.echo(f" {_MAINTAIN_SKILL_DEST}")
ahar/main.py ADDED
@@ -0,0 +1,10 @@
1
+ import click
2
+ from ahar.commands.init import init
3
+
4
+
5
+ @click.group()
6
+ def cli():
7
+ """ahar — agent harness CLI for agentharnesses.io"""
8
+
9
+
10
+ cli.add_command(init)