acumen 0.0.1.dev0__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.
- acumen/__init__.py +160 -0
- acumen/_skills/__init__.py +0 -0
- acumen/_skills/data/SKILL.md +109 -0
- acumen/_skills/data/references/authoring.md +91 -0
- acumen/_skills/data/references/benchmark.md +100 -0
- acumen/_skills/data/references/python-api.md +106 -0
- acumen/_skills/data/references/setup.md +94 -0
- acumen/_skills/data/references/ship.md +53 -0
- acumen/_skills/install.py +185 -0
- acumen/assets/banner.svg +501 -0
- acumen/assets/logo.svg +47 -0
- acumen/bench.py +202 -0
- acumen/cli.py +626 -0
- acumen/config.py +204 -0
- acumen/draft.py +202 -0
- acumen/env.py +602 -0
- acumen/grade.py +104 -0
- acumen/improve.py +596 -0
- acumen/logs.py +255 -0
- acumen/paths.py +164 -0
- acumen/procs.py +195 -0
- acumen/prompts.py +942 -0
- acumen/report.py +1858 -0
- acumen/runner.py +343 -0
- acumen/sandbox.py +153 -0
- acumen/scaffold.py +118 -0
- acumen/ship.py +298 -0
- acumen/skills.py +298 -0
- acumen/taskgen.py +424 -0
- acumen/tasks.py +144 -0
- acumen/transcript.py +77 -0
- acumen-0.0.1.dev0.dist-info/METADATA +168 -0
- acumen-0.0.1.dev0.dist-info/RECORD +36 -0
- acumen-0.0.1.dev0.dist-info/WHEEL +4 -0
- acumen-0.0.1.dev0.dist-info/entry_points.txt +3 -0
- acumen-0.0.1.dev0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# `acumen ship` — put a proven skill inside the package
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
acumen ship --skill v2 [--force] [--model M] [--max-turns N] [--max-usd X]
|
|
5
|
+
[--stream] [--log-dir logs] [--auth auto|session|api]
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
`--skill VERSION` is **required** — there is no implicit "latest" or "best". Run it only
|
|
9
|
+
after the report shows that version earning its place *and* the user has agreed to ship it:
|
|
10
|
+
it writes to the target's real checkout and can open a PR.
|
|
11
|
+
|
|
12
|
+
## What it produces
|
|
13
|
+
|
|
14
|
+
An agent modifies the target checkout so the package gains a `<dist-name>-install-skills`
|
|
15
|
+
console script. The package's users then run, e.g.:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
scanpy-install-skills --agent claude # or codex | agents | claude-science
|
|
19
|
+
scanpy-install-skills --dest ./somewhere # explicit destination
|
|
20
|
+
scanpy-install-skills --print-path # where the bundled skill lives
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
There is **no default framework** — `--agent` or `--dest` is required. The same
|
|
24
|
+
`SKILL.md` + `references/` bundle installs verbatim into every framework; there is no
|
|
25
|
+
per-framework conversion. Destinations are `<root>/skills/<skill_name>`, with roots
|
|
26
|
+
`~/.claude` (`CLAUDE_CONFIG_DIR`), `~/.codex` (`CODEX_HOME`), `~/.agents`, and the active
|
|
27
|
+
org's directory for `claude-science`.
|
|
28
|
+
|
|
29
|
+
Inside the package the agent creates `<import-pkg>/_skills/` with `install.py` (a canonical
|
|
30
|
+
template it must copy verbatim) and `data/` holding the skill files, then wires the console
|
|
31
|
+
script and — the step that silently fails — the **build-backend packaging** so those
|
|
32
|
+
non-`.py` data files actually ship in the wheel. It verifies by building a wheel, installing
|
|
33
|
+
it into a fresh (non-editable) venv, and confirming `SKILL.md` lands.
|
|
34
|
+
|
|
35
|
+
## Delivery depends on `repo`
|
|
36
|
+
|
|
37
|
+
- **GitHub URL** → the agent branches, commits, pushes, and opens a PR with `gh` (it does
|
|
38
|
+
not merge). Needs write access; a rejected push is reported, not worked around.
|
|
39
|
+
- **Local path** → the change is written straight into your working tree, no branch, no
|
|
40
|
+
commit. Review with `git diff`.
|
|
41
|
+
|
|
42
|
+
## Non-obvious behaviour
|
|
43
|
+
|
|
44
|
+
- **The ship agent is deliberately NOT isolated.** Unlike every other acumen agent it runs
|
|
45
|
+
in your real environment: real `HOME`, real network, real git/`gh` credentials, real `uv`,
|
|
46
|
+
with `permission_mode="bypassPermissions"`. Only the model credential is constrained (by
|
|
47
|
+
`--auth`). Run it when you are ready for it to touch your checkout and remote.
|
|
48
|
+
- It refuses to run if the target already declares a `*-install-skills` console script or
|
|
49
|
+
has a `_skills/install.py` — pass `--force` to ship anyway.
|
|
50
|
+
- It ships exactly one version, copied verbatim; it never authors or edits skill text, and
|
|
51
|
+
it writes no tests.
|
|
52
|
+
- Unbounded turns/cost by default. Its final summary (PR URL, packaging changes,
|
|
53
|
+
build-verify result) is printed and returned.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""Install the bundled ``acumen`` skill into an agentic framework's skills directory.
|
|
2
|
+
|
|
3
|
+
Console script (wired as ``<dist>-install-skills`` in ``pyproject.toml``): copy the skill that
|
|
4
|
+
ships inside this package into a chosen framework's skills directory, so an agent can load it.
|
|
5
|
+
The same ``SKILL.md`` + ``references/`` bundle is a cross-framework standard, so it installs
|
|
6
|
+
verbatim — no per-framework conversion.
|
|
7
|
+
|
|
8
|
+
Frameworks (``--agent``):
|
|
9
|
+
|
|
10
|
+
- ``claude`` -> ``~/.claude/skills`` (honours ``CLAUDE_CONFIG_DIR``)
|
|
11
|
+
- ``codex`` -> ``~/.codex/skills`` (honours ``CODEX_HOME``)
|
|
12
|
+
- ``agents`` -> ``~/.agents/skills``
|
|
13
|
+
- ``claude-science`` -> the active org's skills dir, resolved from
|
|
14
|
+
``~/.claude-science/active-org.json``
|
|
15
|
+
|
|
16
|
+
``--dest`` overrides all of them. There is **no default framework**: pass ``--agent`` or
|
|
17
|
+
``--dest``. The skill files live in the ``data/`` directory next to this module and are read via
|
|
18
|
+
``importlib.resources``, so this works from an installed wheel, not just an editable checkout.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
import json
|
|
25
|
+
import os
|
|
26
|
+
import shutil
|
|
27
|
+
import sys
|
|
28
|
+
from importlib import resources
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
|
|
31
|
+
#: The skill name; it installs to ``<framework-skills-dir>/<SKILL_NAME>/``.
|
|
32
|
+
SKILL_NAME = "acumen"
|
|
33
|
+
|
|
34
|
+
#: Framework -> (env var that overrides the config root, default config root). The skills
|
|
35
|
+
#: directory is ``<root>/skills``. ``claude-science`` is resolved separately.
|
|
36
|
+
_AGENT_ROOTS = {
|
|
37
|
+
"codex": ("CODEX_HOME", "~/.codex"),
|
|
38
|
+
"claude": ("CLAUDE_CONFIG_DIR", "~/.claude"),
|
|
39
|
+
"agents": (None, "~/.agents"),
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#: The frameworks ``--agent`` accepts.
|
|
43
|
+
AGENTS = (*sorted(_AGENT_ROOTS), "claude-science")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def source_dir() -> Path:
|
|
47
|
+
"""Return the package-owned skill directory (the bundle that gets copied)."""
|
|
48
|
+
source = Path(str(resources.files(__package__).joinpath("data")))
|
|
49
|
+
if not (source / "SKILL.md").is_file():
|
|
50
|
+
raise RuntimeError(f"packaged skill data is missing: {source}")
|
|
51
|
+
return source
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _claude_science_skills_dir() -> Path:
|
|
55
|
+
"""Resolve the active Claude Science org's skills directory."""
|
|
56
|
+
root = Path("~/.claude-science").expanduser()
|
|
57
|
+
active_org_path = root / "active-org.json"
|
|
58
|
+
try:
|
|
59
|
+
active_org = json.loads(active_org_path.read_text(encoding="utf-8"))
|
|
60
|
+
except (OSError, json.JSONDecodeError) as error:
|
|
61
|
+
raise ValueError(
|
|
62
|
+
"cannot resolve the Claude Science active organization from "
|
|
63
|
+
f"{active_org_path}; pass --dest instead"
|
|
64
|
+
) from error
|
|
65
|
+
org_uuid = active_org.get("org_uuid") if isinstance(active_org, dict) else None
|
|
66
|
+
if (
|
|
67
|
+
not isinstance(org_uuid, str)
|
|
68
|
+
or not org_uuid
|
|
69
|
+
or Path(org_uuid).name != org_uuid
|
|
70
|
+
or org_uuid in {".", ".."}
|
|
71
|
+
):
|
|
72
|
+
raise ValueError(f"invalid Claude Science org_uuid in {active_org_path}; pass --dest instead")
|
|
73
|
+
return root / "orgs" / org_uuid / "skills"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _skills_dir(agent: str) -> Path:
|
|
77
|
+
"""Return the skills directory (parent of the install dir) for a framework."""
|
|
78
|
+
if agent == "claude-science":
|
|
79
|
+
return _claude_science_skills_dir()
|
|
80
|
+
variable, fallback = _AGENT_ROOTS[agent]
|
|
81
|
+
root = os.environ.get(variable) if variable is not None else None
|
|
82
|
+
return Path(root or fallback).expanduser() / "skills"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def resolve_dest(agent: str | None, dest: Path | None) -> Path:
|
|
86
|
+
"""Resolve the install destination from ``--agent`` / ``--dest``.
|
|
87
|
+
|
|
88
|
+
``--dest`` wins. With neither, raise ``ValueError`` — there is no default framework.
|
|
89
|
+
"""
|
|
90
|
+
if dest is not None:
|
|
91
|
+
return dest.expanduser()
|
|
92
|
+
if agent is None:
|
|
93
|
+
raise ValueError("pass --agent {" + ",".join(AGENTS) + "} or --dest to choose where to install")
|
|
94
|
+
return _skills_dir(agent) / SKILL_NAME
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _snapshot(root: Path) -> dict[str, bytes]:
|
|
98
|
+
"""Map each file under ``root`` to its bytes, for exact tree comparison."""
|
|
99
|
+
return {
|
|
100
|
+
str(item.relative_to(root)): item.read_bytes()
|
|
101
|
+
for item in root.rglob("*")
|
|
102
|
+
if item.is_file()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _matches(source: Path, target: Path) -> bool:
|
|
107
|
+
"""Report whether ``target`` is a byte-for-byte copy of ``source``."""
|
|
108
|
+
return target.is_dir() and _snapshot(source) == _snapshot(target)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def main(argv: list[str] | None = None) -> int:
|
|
112
|
+
"""Install the bundled skill; entry point for the ``<dist>-install-skills`` script."""
|
|
113
|
+
parser = argparse.ArgumentParser(
|
|
114
|
+
description=f"Install the {SKILL_NAME} skill bundled with this package into an agent's skills directory.",
|
|
115
|
+
)
|
|
116
|
+
parser.add_argument(
|
|
117
|
+
"--agent",
|
|
118
|
+
choices=AGENTS,
|
|
119
|
+
default=None,
|
|
120
|
+
help="framework to install into (no default — pass this or --dest)",
|
|
121
|
+
)
|
|
122
|
+
parser.add_argument(
|
|
123
|
+
"--dest",
|
|
124
|
+
type=Path,
|
|
125
|
+
default=None,
|
|
126
|
+
help="exact skills directory to install into (overrides --agent)",
|
|
127
|
+
)
|
|
128
|
+
parser.add_argument(
|
|
129
|
+
"--force",
|
|
130
|
+
action="store_true",
|
|
131
|
+
help="overwrite an existing installation that differs from the bundled skill",
|
|
132
|
+
)
|
|
133
|
+
action = parser.add_mutually_exclusive_group()
|
|
134
|
+
action.add_argument(
|
|
135
|
+
"--check",
|
|
136
|
+
action="store_true",
|
|
137
|
+
help="report whether the installed skill matches the bundled one; do not install",
|
|
138
|
+
)
|
|
139
|
+
action.add_argument(
|
|
140
|
+
"--print-path",
|
|
141
|
+
action="store_true",
|
|
142
|
+
help="print the bundled skill's location inside the package and exit",
|
|
143
|
+
)
|
|
144
|
+
args = parser.parse_args(argv)
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
source = source_dir()
|
|
148
|
+
if args.print_path:
|
|
149
|
+
print(source)
|
|
150
|
+
return 0
|
|
151
|
+
if args.check:
|
|
152
|
+
target = resolve_dest(args.agent, args.dest)
|
|
153
|
+
if not target.exists():
|
|
154
|
+
print(f"{SKILL_NAME} skill is not installed at {target}", file=sys.stderr)
|
|
155
|
+
return 1
|
|
156
|
+
if _matches(source, target):
|
|
157
|
+
print(f"{SKILL_NAME} skill at {target} matches the bundled copy")
|
|
158
|
+
return 0
|
|
159
|
+
print(f"{SKILL_NAME} skill at {target} differs from the bundled copy", file=sys.stderr)
|
|
160
|
+
return 1
|
|
161
|
+
|
|
162
|
+
dest = resolve_dest(args.agent, args.dest)
|
|
163
|
+
if dest.exists():
|
|
164
|
+
if _matches(source, dest):
|
|
165
|
+
print(f"{SKILL_NAME} skill already up to date at {dest}")
|
|
166
|
+
return 0
|
|
167
|
+
if not args.force:
|
|
168
|
+
print(f"{dest} already exists and differs; pass --force to overwrite", file=sys.stderr)
|
|
169
|
+
return 1
|
|
170
|
+
if dest.is_dir():
|
|
171
|
+
shutil.rmtree(dest)
|
|
172
|
+
else:
|
|
173
|
+
dest.unlink()
|
|
174
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
175
|
+
shutil.copytree(source, dest)
|
|
176
|
+
except (OSError, RuntimeError, ValueError) as error:
|
|
177
|
+
print(f"error: {error}", file=sys.stderr)
|
|
178
|
+
return 1
|
|
179
|
+
|
|
180
|
+
print(f"installed the {SKILL_NAME} skill to {dest}")
|
|
181
|
+
return 0
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
if __name__ == "__main__":
|
|
185
|
+
raise SystemExit(main())
|