agent-apprenticeship 0.1.5 → 0.1.6
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.
package/README.md
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# Agent Apprenticeship
|
|
2
|
-
|
|
3
1
|
The living ecosystem where AI agents learn from real-world work through iterative workflow loops, reusable experience, and collective training signal exchange.
|
|
4
2
|
|
|
5
3
|
As agents move into long-horizon, economically valuable work, Agent Apprenticeship creates the open infrastructure where real-world tasks generate reusable learning signals and complex workflows advance through agent loops that turn execution into shared improvement.
|
|
@@ -11,198 +9,3 @@ Agent Apprenticeship is built for iterative workflow loops across domains, from
|
|
|
11
9
|
Agent Apprenticeship is now available for anyone to start using with local agents including Codex, Cursor, Claude Code, OpenClaw, OpenCode, Hermes Agent, and custom agents, alongside different model providers. Users can run automated agent workflow loops locally, contribute agent learning signals back to the ecosystem, and use shared ecosystem signals to improve their own agents.
|
|
12
10
|
|
|
13
11
|
Agent Apprenticeship is about the future of work and the economic value of agents. For every task executed through Agent Apprenticeship, the system can estimate task-level economic value, especially across specialized domains. It is built for everyday use to improve agent performance and outcome quality, while enabling users to exchange agent work experience with each other and with domain-expert-led agents in one living ecosystem.
|
|
14
|
-
|
|
15
|
-
## Install
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npx agent-apprenticeship init
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm install -g agent-apprenticeship
|
|
23
|
-
apprentice init
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
The installed command is:
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
apprentice
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
The long-form command also remains available:
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
agent-apprenticeship
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Quickstart
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
apprentice init
|
|
42
|
-
apprentice settings
|
|
43
|
-
apprentice run "Create a short market map for AI procurement tools."
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Runs print the artifacts path and Contribution Bundle path.
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
apprentice ecosystem contribute <bundle_path>
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Public ecosystem:
|
|
53
|
-
|
|
54
|
-
https://github.com/Forsy-AI/agent-apprenticeship
|
|
55
|
-
|
|
56
|
-
## Apprentice Agents
|
|
57
|
-
|
|
58
|
-
Selected v0 Apprentice Agents:
|
|
59
|
-
|
|
60
|
-
* Codex
|
|
61
|
-
* Cursor
|
|
62
|
-
* Claude Code
|
|
63
|
-
* OpenClaw
|
|
64
|
-
* OpenCode
|
|
65
|
-
* Hermes Agent
|
|
66
|
-
* Custom
|
|
67
|
-
|
|
68
|
-
Agent Apprenticeship auto-detects installed CLIs. If multiple are detected, choose one during setup.
|
|
69
|
-
|
|
70
|
-
Custom lets you provide a command template:
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
apprentice configure agent custom --command-template "my-agent run --workspace {workspace} --prompt-file {prompt_file}"
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## Mentor Model Providers
|
|
77
|
-
|
|
78
|
-
Store local keys in:
|
|
79
|
-
|
|
80
|
-
```text
|
|
81
|
-
~/.agent-apprenticeship/.env.local
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
Example:
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
OPENAI_API_KEY=""
|
|
88
|
-
ANTHROPIC_API_KEY=""
|
|
89
|
-
GEMINI_API_KEY=""
|
|
90
|
-
OPENROUTER_API_KEY=""
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Configure:
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
apprentice configure model
|
|
97
|
-
apprentice doctor
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Mentor Modes
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
apprentice run "..." --mentor-mode model-assisted
|
|
104
|
-
apprentice run "..." --mentor-mode expert-led
|
|
105
|
-
apprentice run "..." --mentor-mode hybrid
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
* `model-assisted`: Mentor Model Provider handles the mentor loop.
|
|
109
|
-
* `expert-led`: human expert checkpoints guide the mentor loop.
|
|
110
|
-
* `hybrid`: Mentor Model Provider drafts and human expert checkpoints approve or edit.
|
|
111
|
-
|
|
112
|
-
## Seed Dataset
|
|
113
|
-
|
|
114
|
-
The seed dataset is included under:
|
|
115
|
-
|
|
116
|
-
```text
|
|
117
|
-
seed_dataset/
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
Explore seed tasks:
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
apprentice ecosystem list
|
|
124
|
-
apprentice ecosystem search cloud
|
|
125
|
-
apprentice ecosystem inspect aa-seed-task-501
|
|
126
|
-
apprentice ecosystem pull aa-seed-task-501
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
## Ecosystem Learning
|
|
130
|
-
|
|
131
|
-
Create Experience Packs from ecosystem experience:
|
|
132
|
-
|
|
133
|
-
```bash
|
|
134
|
-
apprentice learn create aa-seed-task-501
|
|
135
|
-
apprentice learn preview <pack_id>
|
|
136
|
-
apprentice learn replay <pack_id>
|
|
137
|
-
apprentice learn keep <pack_id>
|
|
138
|
-
apprentice run "Create a related incident response checklist." --experience-pack <pack_id>
|
|
139
|
-
apprentice learn revert <pack_id>
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Use active packs explicitly:
|
|
143
|
-
|
|
144
|
-
```bash
|
|
145
|
-
apprentice run "..." --use-active-experience-packs
|
|
146
|
-
apprentice run "..." --no-experience-packs
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
## Contribution Bundles
|
|
150
|
-
|
|
151
|
-
Runs produce Contribution Bundles.
|
|
152
|
-
|
|
153
|
-
Contribute one to the public ecosystem:
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
apprentice ecosystem contribute <bundle_path>
|
|
157
|
-
apprentice bundle contribute <bundle_path>
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
Public ecosystem:
|
|
161
|
-
|
|
162
|
-
https://github.com/Forsy-AI/agent-apprenticeship
|
|
163
|
-
|
|
164
|
-
## Ecosystem Auto-Share
|
|
165
|
-
|
|
166
|
-
Default mode is Manual.
|
|
167
|
-
|
|
168
|
-
```bash
|
|
169
|
-
apprentice ecosystem configure --repo Forsy-AI/agent-apprenticeship
|
|
170
|
-
apprentice ecosystem configure --auto-share manual
|
|
171
|
-
apprentice ecosystem configure --auto-share ask
|
|
172
|
-
apprentice ecosystem configure --auto-share automatic
|
|
173
|
-
apprentice ecosystem status
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
Requirements:
|
|
177
|
-
|
|
178
|
-
* GitHub CLI installed
|
|
179
|
-
* `gh` authenticated
|
|
180
|
-
* ecosystem repo configured
|
|
181
|
-
|
|
182
|
-
## Search, Inspect, Pull
|
|
183
|
-
|
|
184
|
-
Discover and export ecosystem experience:
|
|
185
|
-
|
|
186
|
-
```bash
|
|
187
|
-
apprentice ecosystem search <query>
|
|
188
|
-
apprentice ecosystem inspect <id>
|
|
189
|
-
apprentice ecosystem pull <id>
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
## Public Repo Structure
|
|
193
|
-
|
|
194
|
-
```text
|
|
195
|
-
seed_dataset/
|
|
196
|
-
ecosystem/
|
|
197
|
-
ecosystem/contributions/
|
|
198
|
-
schemas/
|
|
199
|
-
examples/
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
## Development Commands
|
|
203
|
-
|
|
204
|
-
```bash
|
|
205
|
-
.venv/bin/python -m pytest -q tests
|
|
206
|
-
PYTHONPATH=src .venv/bin/python -m compileall -q src tests scripts examples
|
|
207
|
-
bash scripts/export_public_repo.sh
|
|
208
|
-
```
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agent-apprenticeship"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.6"
|
|
8
8
|
description = "Open framework for turning real agent work into transferable agent experience"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""Agent Apprenticeship framework."""
|
|
2
|
-
__version__ = "0.1.
|
|
2
|
+
__version__ = "0.1.6"
|
|
@@ -48,6 +48,7 @@ from .config import (
|
|
|
48
48
|
)
|
|
49
49
|
from .openai_structured import run_llm_smoke, format_smoke_counters
|
|
50
50
|
from .env import contains_secret, redact_secrets
|
|
51
|
+
from .public_sanitizer import sanitize_public_obj, sanitize_public_text
|
|
51
52
|
from .command_discovery import AGENT_COMMAND_CANDIDATES, resolve_command, resolve_agent_command
|
|
52
53
|
from .integration_status import integrations_report
|
|
53
54
|
from .certification import certification_exit_code, run_certification_matrix
|
|
@@ -2188,6 +2189,55 @@ def _zip_dir(src: Path, dst: Path) -> str:
|
|
|
2188
2189
|
return f"sha256:{digest}"
|
|
2189
2190
|
|
|
2190
2191
|
|
|
2192
|
+
def _sanitize_submission_copy(root: Path) -> None:
|
|
2193
|
+
text_suffixes = {
|
|
2194
|
+
".json",
|
|
2195
|
+
".jsonl",
|
|
2196
|
+
".md",
|
|
2197
|
+
".txt",
|
|
2198
|
+
".yaml",
|
|
2199
|
+
".yml",
|
|
2200
|
+
".csv",
|
|
2201
|
+
".tsv",
|
|
2202
|
+
".log",
|
|
2203
|
+
}
|
|
2204
|
+
for path in root.rglob("*"):
|
|
2205
|
+
if not path.is_file() or path.stat().st_size > 5_000_000:
|
|
2206
|
+
continue
|
|
2207
|
+
if path.suffix.lower() not in text_suffixes:
|
|
2208
|
+
continue
|
|
2209
|
+
raw = path.read_text(errors="ignore")
|
|
2210
|
+
if path.suffix.lower() == ".json":
|
|
2211
|
+
try:
|
|
2212
|
+
data = json.loads(raw or "{}")
|
|
2213
|
+
except Exception:
|
|
2214
|
+
path.write_text(sanitize_public_text(raw) or "")
|
|
2215
|
+
else:
|
|
2216
|
+
if isinstance(data, dict):
|
|
2217
|
+
write_json(path, sanitize_public_obj(data))
|
|
2218
|
+
elif isinstance(data, list):
|
|
2219
|
+
path.write_text(json.dumps(sanitize_public_obj({"items": data})["items"], indent=2, sort_keys=True) + "\n")
|
|
2220
|
+
else:
|
|
2221
|
+
path.write_text(sanitize_public_text(raw) or "")
|
|
2222
|
+
elif path.suffix.lower() == ".jsonl":
|
|
2223
|
+
rows = []
|
|
2224
|
+
for line in raw.splitlines():
|
|
2225
|
+
if not line.strip():
|
|
2226
|
+
continue
|
|
2227
|
+
try:
|
|
2228
|
+
data = json.loads(line)
|
|
2229
|
+
except Exception:
|
|
2230
|
+
rows.append(json.dumps(sanitize_public_text(line) or "", sort_keys=True))
|
|
2231
|
+
else:
|
|
2232
|
+
if isinstance(data, dict):
|
|
2233
|
+
rows.append(json.dumps(sanitize_public_obj(data), sort_keys=True))
|
|
2234
|
+
else:
|
|
2235
|
+
rows.append(json.dumps(sanitize_public_obj({"item": data})["item"], sort_keys=True))
|
|
2236
|
+
path.write_text("\n".join(rows) + ("\n" if rows else ""))
|
|
2237
|
+
else:
|
|
2238
|
+
path.write_text(sanitize_public_text(raw) or "")
|
|
2239
|
+
|
|
2240
|
+
|
|
2191
2241
|
def _create_ecosystem_submission(bundle: Path) -> tuple[Path, Path, dict]:
|
|
2192
2242
|
bundle = _safe_bundle_path(bundle)
|
|
2193
2243
|
secret_hits = _bundle_secret_hits(bundle)
|
|
@@ -2206,6 +2256,7 @@ def _create_ecosystem_submission(bundle: Path) -> tuple[Path, Path, dict]:
|
|
|
2206
2256
|
submission_dir / "contribution_bundle",
|
|
2207
2257
|
ignore=shutil.ignore_patterns(".env", ".env.local", "__pycache__", "*.pyc"),
|
|
2208
2258
|
)
|
|
2259
|
+
_sanitize_submission_copy(submission_dir / "contribution_bundle")
|
|
2209
2260
|
package_zip = bundle.parent / f"{bundle.name}_ecosystem_submission.zip"
|
|
2210
2261
|
metadata = _bundle_submission_metadata(bundle, package_name=package_zip.name)
|
|
2211
2262
|
write_json(submission_dir / "ecosystem_submission.json", metadata)
|
|
@@ -2757,9 +2808,9 @@ def ecosystem_contribute(
|
|
|
2757
2808
|
typer.echo("")
|
|
2758
2809
|
typer.echo(f"Bundle ID: {metadata.get('bundle_id')}")
|
|
2759
2810
|
typer.echo(f"Title: {metadata.get('title')}")
|
|
2760
|
-
typer.echo(f"Bundle: {bundle}")
|
|
2761
|
-
typer.echo(f"Submission package: {package_zip}")
|
|
2762
|
-
typer.echo(
|
|
2811
|
+
typer.echo(f"Bundle folder: {bundle.name}")
|
|
2812
|
+
typer.echo(f"Submission package: {package_zip.name}")
|
|
2813
|
+
typer.echo("Submission metadata: ecosystem_submission/ecosystem_submission.json")
|
|
2763
2814
|
if result["contribution_created"]:
|
|
2764
2815
|
typer.echo(f"Public contribution URL: {result['contribution_url']}")
|
|
2765
2816
|
typer.echo("No bundle files were uploaded automatically. Attach or submit the generated package according to the repo instructions.")
|
|
@@ -2769,7 +2820,7 @@ def ecosystem_contribute(
|
|
|
2769
2820
|
typer.echo(str(result.get("gh_error") or ""))
|
|
2770
2821
|
elif target_repo and _gh_path() and _gh_authenticated() and dry_run:
|
|
2771
2822
|
typer.echo("Dry run: no GitHub issue was created.")
|
|
2772
|
-
typer.echo(f"Would run: gh issue create --repo {target_repo} --title \"Contribution Bundle: {metadata.get('bundle_id')}\" --body-file
|
|
2823
|
+
typer.echo(f"Would run: gh issue create --repo {target_repo} --title \"Contribution Bundle: {metadata.get('bundle_id')}\" --body-file GITHUB_ISSUE_BODY.md")
|
|
2773
2824
|
else:
|
|
2774
2825
|
typer.echo("No upload was performed in v0.")
|
|
2775
2826
|
typer.echo(f"Public ecosystem: {_ecosystem_repo_url(target_repo)}")
|
|
@@ -2780,8 +2831,8 @@ def ecosystem_contribute(
|
|
|
2780
2831
|
typer.echo("")
|
|
2781
2832
|
typer.echo("Manual public submission steps:")
|
|
2782
2833
|
typer.echo(f"1. Open {_ecosystem_repo_url(target_repo)} in GitHub.")
|
|
2783
|
-
typer.echo(
|
|
2784
|
-
typer.echo(f"3. Attach or share the submission package: {package_zip}")
|
|
2834
|
+
typer.echo("2. Create a new issue using: ecosystem_submission/GITHUB_ISSUE_BODY.md")
|
|
2835
|
+
typer.echo(f"3. Attach or share the submission package: {package_zip.name}")
|
|
2785
2836
|
typer.echo(f"Community Slack: {SLACK_LINK}")
|
|
2786
2837
|
|
|
2787
2838
|
|
|
@@ -3123,8 +3174,8 @@ def bundle_contribute(path: Path=typer.Argument(..., help='Contribution Bundle f
|
|
|
3123
3174
|
typer.echo(str(path))
|
|
3124
3175
|
typer.echo('')
|
|
3125
3176
|
typer.echo('No upload was performed by this command.')
|
|
3126
|
-
typer.echo(f"Submission package: {package_zip}")
|
|
3127
|
-
typer.echo(
|
|
3177
|
+
typer.echo(f"Submission package: {package_zip.name}")
|
|
3178
|
+
typer.echo("Submission metadata: ecosystem_submission/ecosystem_submission.json")
|
|
3128
3179
|
typer.echo('')
|
|
3129
3180
|
typer.echo('Contribute to public ecosystem:')
|
|
3130
3181
|
typer.echo(f'apprentice ecosystem contribute {path}')
|
|
@@ -16,11 +16,11 @@ CONTROLLER_TELEMETRY_KEYS={
|
|
|
16
16
|
}
|
|
17
17
|
CONTROLLER_TELEMETRY_PATTERNS=list(CONTROLLER_TELEMETRY_KEYS)
|
|
18
18
|
PUBLIC_OMIT_KEYS={
|
|
19
|
-
'source_url_or_ref','source_kind','source_url','source_ref','source_license',
|
|
19
|
+
'source_url_or_ref','source_kind','source_url','source_ref','source_basis','source_license',
|
|
20
20
|
'expected_pay','expected_apprentice_pay',
|
|
21
21
|
'evaluation_mode','data_sharing_level','sensitive_info_masking',
|
|
22
22
|
}
|
|
23
|
-
_ABS_LOCAL_PATH_RE=re.compile(r"(/Users/[^\s\"\']+|/home/[^\s\"\']+|/private/[^\s\"\']+|/tmp/[^\s\"\']+)")
|
|
23
|
+
_ABS_LOCAL_PATH_RE=re.compile(r"(/Users/[^\s\"\']+|/home/[^\s\"\']+|/private/[^\s\"\']+|/tmp/[^\s\"\']+|/var/folders/[^\s\"\']+)")
|
|
24
24
|
_USAGE_RE=re.compile(r"(you['’]?ve hit your usage limit|usage limit|rate limit|quota)", re.I)
|
|
25
25
|
PUBLIC_TEXT_REPLACEMENTS=[
|
|
26
26
|
("source_url_or_ref", "reference_or_context"),
|
|
@@ -29,6 +29,7 @@ PUBLIC_TEXT_REPLACEMENTS=[
|
|
|
29
29
|
("source_urls", "reference_links"),
|
|
30
30
|
("source_url", "reference_link"),
|
|
31
31
|
("source_ref", "reference_id"),
|
|
32
|
+
("source_basis", "reference_basis"),
|
|
32
33
|
("source_kind", "reference_kind"),
|
|
33
34
|
("source_license", "reference_license"),
|
|
34
35
|
("expected_apprentice_pay", "expected_economic_value_for_agent_apprentice"),
|