code2okf 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.
- code2okf/SPEC.md +1006 -0
- code2okf/__init__.py +8 -0
- code2okf/cli.py +234 -0
- code2okf/clis/inspectmd/pyproject.toml +40 -0
- code2okf/clis/inspectmd/src/inspectmd/__init__.py +8 -0
- code2okf/clis/inspectmd/src/inspectmd/__main__.py +5 -0
- code2okf/clis/inspectmd/src/inspectmd/cli.py +159 -0
- code2okf/clis/inspectmd/src/inspectmd/parse.py +212 -0
- code2okf/clis/inspectokf/pyproject.toml +40 -0
- code2okf/clis/inspectokf/src/inspectokf/__init__.py +8 -0
- code2okf/clis/inspectokf/src/inspectokf/__main__.py +5 -0
- code2okf/clis/inspectokf/src/inspectokf/cli.py +104 -0
- code2okf/clis/merkleokf/pyproject.toml +40 -0
- code2okf/clis/merkleokf/src/merkleokf/__init__.py +8 -0
- code2okf/clis/merkleokf/src/merkleokf/__main__.py +5 -0
- code2okf/clis/merkleokf/src/merkleokf/cli.py +121 -0
- code2okf/clis/merkleokf/src/merkleokf/merkle.py +145 -0
- code2okf/clis/sizeokf/pyproject.toml +40 -0
- code2okf/clis/sizeokf/src/sizeokf/__init__.py +8 -0
- code2okf/clis/sizeokf/src/sizeokf/__main__.py +5 -0
- code2okf/clis/sizeokf/src/sizeokf/cli.py +93 -0
- code2okf/clis/sizeokf/src/sizeokf/sizes.py +155 -0
- code2okf/compile.py +267 -0
- code2okf/events.py +86 -0
- code2okf/kit/README.md +128 -0
- code2okf/kit/files/home/.local/lib/code2okf/mount-state.sh +48 -0
- code2okf/kit/files/home/.pi/agent/AGENTS.md +185 -0
- code2okf/kit/files/home/.pi/agent/models.json +84 -0
- code2okf/kit/files/home/.pi/agent/settings.json +7 -0
- code2okf/kit/files/home/.pi/agent/skills/compile-okf/SKILL.md +142 -0
- code2okf/kit/files/home/.pi/agent/skills/compile-okf/scripts/check-okf.sh +155 -0
- code2okf/kit/files/home/.pi/agent/skills/compile-okf/scripts/frontmatter-guard.py +289 -0
- code2okf/kit/files/home/.pi/agent/skills/curate-okf/SKILL.md +68 -0
- code2okf/kit/files/home/.pi/agent/skills/inspect-md/SKILL.md +52 -0
- code2okf/kit/files/home/.pi/agent/skills/inspect-okf/SKILL.md +47 -0
- code2okf/kit/files/home/.pi/agent/skills/merkle-okf/SKILL.md +59 -0
- code2okf/kit/files/home/.pi/agent/skills/size-okf/SKILL.md +52 -0
- code2okf/kit/spec.yaml +312 -0
- code2okf/resources.py +74 -0
- code2okf/sandbox.py +266 -0
- code2okf/workbench.py +572 -0
- code2okf-0.1.0.dist-info/METADATA +391 -0
- code2okf-0.1.0.dist-info/RECORD +48 -0
- code2okf-0.1.0.dist-info/WHEEL +4 -0
- code2okf-0.1.0.dist-info/entry_points.txt +2 -0
- code2okf-0.1.0.dist-info/licenses/LICENSE +21 -0
- code2okf-0.1.0.dist-info/licenses/LICENSE-OKF-SPEC.txt +203 -0
- code2okf-0.1.0.dist-info/licenses/NOTICE-OKF-SPEC.md +37 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: code2okf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Compile Markdown into an OKF wiki with the Pi coding agent, via a sandboxed sbx runtime
|
|
5
|
+
Project-URL: Homepage, https://github.com/lars20070/code2okf
|
|
6
|
+
Project-URL: Changelog, https://github.com/lars20070/code2okf/blob/main/CHANGELOG.md
|
|
7
|
+
Project-URL: Issues, https://github.com/lars20070/code2okf/issues
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
License-File: LICENSE-OKF-SPEC.txt
|
|
11
|
+
License-File: NOTICE-OKF-SPEC.md
|
|
12
|
+
Keywords: agent,knowledge-base,markdown,okf,sandbox,wiki
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: MacOS
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Topic :: Documentation
|
|
20
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# code2okf
|
|
25
|
+
|
|
26
|
+
[](https://github.com/lars20070/code2okf/actions/workflows/ci.yml)
|
|
27
|
+
[](https://github.com/lars20070/code2okf/releases/latest)
|
|
28
|
+
[](LICENSE)
|
|
29
|
+
|
|
30
|
+
Compile Markdown documents into an OKF knowledge base with a coding agent.
|
|
31
|
+
|
|
32
|
+
Point `code2okf` at a Markdown file or folder and the [Pi coding
|
|
33
|
+
agent](https://pi.dev) writes a wiki into the output directory: a page per
|
|
34
|
+
topic, an index in every directory, links between them, and a log of what each
|
|
35
|
+
run changed. OKF,
|
|
36
|
+
the [Open Knowledge
|
|
37
|
+
Format](https://github.com/GoogleCloudPlatform/open-knowledge-format),
|
|
38
|
+
is a tree of Markdown files with YAML frontmatter and nothing else — no schema
|
|
39
|
+
registry, no server, nothing to install. The agent takes one source document per
|
|
40
|
+
run and folds it into the wiki already on disk, so documents accumulate rather
|
|
41
|
+
than overwrite. [SPEC.md](SPEC.md) is the OKF specification the wiki is built
|
|
42
|
+
against; the agent reads it at the start of every run, and it outranks any
|
|
43
|
+
other instructions.
|
|
44
|
+
|
|
45
|
+
<!-- cspell:disable -->
|
|
46
|
+
|
|
47
|
+
```mermaid
|
|
48
|
+
flowchart LR
|
|
49
|
+
subgraph IN[" "]
|
|
50
|
+
direction TB
|
|
51
|
+
SPEC@{ shape: doc, label: "okf spec<br>SPEC.md"}
|
|
52
|
+
MD@{ shape: docs, label: "source documents<br>md/*.md"}
|
|
53
|
+
STATE["session traces<br> + message board<br/>~/.local/state/code2okf"]
|
|
54
|
+
DRV["code2okf<br/>the host driver"]
|
|
55
|
+
KIT["kits/code2okf/spec.yaml<br/>kits/code2okf/files/"]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
subgraph VM["sbx microVM"]
|
|
59
|
+
PI["Pi agent with<br/>/compile-okf skill"]
|
|
60
|
+
TOOLS["skills<br>/inspectmd<br/>/inspectokf<br/>/sizeokf<br/>/merkleokf"]
|
|
61
|
+
LINT["okfctl linter"]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
subgraph OUT[" "]
|
|
65
|
+
direction TB
|
|
66
|
+
OKF@{ shape: docs, label: "okf/<br/>the wiki"}
|
|
67
|
+
NET("OpenRouter hub")
|
|
68
|
+
end
|
|
69
|
+
NET1("DeepInfra")
|
|
70
|
+
NET2("...")
|
|
71
|
+
|
|
72
|
+
SPEC -.->|"outranks all"| PI
|
|
73
|
+
MD ==>|"read by"| PI
|
|
74
|
+
STATE -.->|"mounts"| VM
|
|
75
|
+
STATE ~~~ PI
|
|
76
|
+
DRV -->|"sbx exec"| PI
|
|
77
|
+
KIT -->|"builds"| VM
|
|
78
|
+
PI -.->|"uses"| TOOLS
|
|
79
|
+
PI -.->|"runs"| LINT
|
|
80
|
+
LINT -.->|"must pass"| OKF
|
|
81
|
+
PI ==>|"writes"| OKF
|
|
82
|
+
PI -->|"via sbx proxy"| NET
|
|
83
|
+
NET -->|"BYOK"| NET1 & NET2
|
|
84
|
+
|
|
85
|
+
classDef data fill:aliceblue,stroke:steelblue,stroke-width:2px,color:#10314F
|
|
86
|
+
classDef host fill:antiquewhite,stroke:darkgoldenrod,stroke-width:2px,color:#4A2E05
|
|
87
|
+
classDef helper fill:#E3F2F1,stroke:#0E7C86,stroke-width:2px,color:#0B3D40
|
|
88
|
+
classDef agent fill:mistyrose,stroke:firebrick,stroke-width:2px,color:#5A1710
|
|
89
|
+
classDef ext fill:whitesmoke,stroke:lightslategray,stroke-width:1.5px,color:#3A4250
|
|
90
|
+
class MD,SPEC,STATE,OKF data
|
|
91
|
+
class KIT,DRV host
|
|
92
|
+
class TOOLS,LINT helper
|
|
93
|
+
class PI agent
|
|
94
|
+
class NET,NET1,NET2 ext
|
|
95
|
+
style VM fill:whitesmoke,stroke:lightslategray,stroke-width:1.5px
|
|
96
|
+
style IN fill:none,stroke:none
|
|
97
|
+
style OUT fill:none,stroke:none
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
<br>*Host tooling (amber) builds the microVM from the kit and drives it with one
|
|
101
|
+
`sbx exec` per source document. Inside, the Pi agent (red) runs the
|
|
102
|
+
`/compile-okf` skill: it reads the source documents and `SPEC.md` (blue) and writes the wiki into `okf/` (blue), the
|
|
103
|
+
only content it may change. Skills and the linter (teal) support it — the four
|
|
104
|
+
tools survey the source markdown and wiki, and the linter must pass before a run ends. Session
|
|
105
|
+
state (blue) is mounted from the host, so transcripts outlive the sandbox.
|
|
106
|
+
Model calls leave the VM only through the sbx proxy, which injects the
|
|
107
|
+
OpenRouter key; OpenRouter routes them to DeepInfra or other providers (gray).*
|
|
108
|
+
|
|
109
|
+
<!-- cspell:enable -->
|
|
110
|
+
|
|
111
|
+
## Contents
|
|
112
|
+
|
|
113
|
+
- [Requirements](#requirements)
|
|
114
|
+
- [Quickstart](#quickstart)
|
|
115
|
+
- [Session state](#session-state)
|
|
116
|
+
- [How it works](#how-it-works)
|
|
117
|
+
- [What lands in okf/](#what-lands-in-okf)
|
|
118
|
+
- [Getting Markdown in](#getting-markdown-in)
|
|
119
|
+
- [Set up the OpenRouter key](#set-up-the-openrouter-key)
|
|
120
|
+
- [Troubleshooting](#troubleshooting)
|
|
121
|
+
- [Development](#development)
|
|
122
|
+
- [Getting help](#getting-help)
|
|
123
|
+
- [License](#license)
|
|
124
|
+
|
|
125
|
+
## Requirements
|
|
126
|
+
|
|
127
|
+
- macOS with [Homebrew](https://brew.sh), or
|
|
128
|
+
Linux with [KVM](https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine). Docker Desktop is not
|
|
129
|
+
required.
|
|
130
|
+
- [sbx](https://github.com/docker/sbx-releases) 0.43.0 is required. sbx is experimental. A later version may break `code2okf`.
|
|
131
|
+
- An [OpenRouter](https://openrouter.ai) API key, which pays for the model the
|
|
132
|
+
agent runs on.
|
|
133
|
+
- [uv](https://docs.astral.sh/uv/), which installs and runs `code2okf`.
|
|
134
|
+
- `git`. `make` and `jq` are needed only for the developer tasks in
|
|
135
|
+
[the contributing guide](CONTRIBUTING.md), not for compiling.
|
|
136
|
+
- [okfctl](https://github.com/cwest/okfctl), only for the host-side `make
|
|
137
|
+
check-okf`: `brew install cwest/tap/okfctl`. The sandbox installs its own
|
|
138
|
+
pinned copy, so a compile does not need it.
|
|
139
|
+
|
|
140
|
+
## Quickstart
|
|
141
|
+
|
|
142
|
+
Install the sandbox CLI and sign in.
|
|
143
|
+
|
|
144
|
+
[macOS:](https://docs.docker.com/ai/sandboxes/install/#install-on-macos)
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
brew trust docker/tap
|
|
148
|
+
brew install docker/tap/sbx
|
|
149
|
+
sbx login
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
[Linux:](https://docs.docker.com/ai/sandboxes/install/#linux)
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
curl -fsSL https://get.docker.com | sudo REPO_ONLY=1 sh
|
|
156
|
+
sudo apt-get install docker-sbx
|
|
157
|
+
sudo usermod -aG kvm "$USER" && newgrp kvm
|
|
158
|
+
sbx login
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Hand sbx your OpenRouter key once — see [Set up the OpenRouter
|
|
162
|
+
key](#set-up-the-openrouter-key). Then install the command and compile:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
uv tool install code2okf # from PyPI
|
|
166
|
+
code2okf my-document.md # the wiki lands in ./okf
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`uvx code2okf …` runs it without installing anything;
|
|
170
|
+
`uv tool install git+https://github.com/lars20070/code2okf` installs the latest
|
|
171
|
+
commit, and `uv tool install .` a clone you have edited. The command takes files
|
|
172
|
+
or folders, and `-o` chooses the output:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
code2okf -o wikis/handbook docs/handbook/ # every *.md in that folder
|
|
176
|
+
code2okf -n 20 long-document.md # raise the iteration cap
|
|
177
|
+
code2okf --dry-run md/ # resolve and print, run nothing
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Session state defaults to `~/.local/state/code2okf`; export `XDG_STATE_HOME` to
|
|
181
|
+
put it elsewhere. Changing it once a sandbox exists takes one manual step — see
|
|
182
|
+
[Session state](#session-state).
|
|
183
|
+
|
|
184
|
+
Each document gets its own agent run, and each run reports the wiki's root hash
|
|
185
|
+
before and after (tool calls and agent prose stream in between):
|
|
186
|
+
|
|
187
|
+
```text
|
|
188
|
+
Compiling document md/my-document.md (iteration 1)
|
|
189
|
+
7f3c1a9d4e02 -> b481d05c6a17
|
|
190
|
+
Compiling document md/my-document.md (iteration 2)
|
|
191
|
+
b481d05c6a17 -> b481d05c6a17
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`-o` defaults to `./okf`, which this repository gitignores, so generated pages
|
|
195
|
+
stay out of the repo. `md/` is tracked and ships with sample documents, so
|
|
196
|
+
`code2okf md/` has something to compile straight away. `code2okf` manages its
|
|
197
|
+
output directory: it creates one that does not exist, adopts one that is empty
|
|
198
|
+
or already an OKF bundle root, and refuses anything else rather than deleting
|
|
199
|
+
what it finds.
|
|
200
|
+
|
|
201
|
+
## Session state
|
|
202
|
+
|
|
203
|
+
Pi writes transcripts through its native `~/.pi/agent/sessions` path. Inside
|
|
204
|
+
the sandbox that directory is bind-mounted onto the host's
|
|
205
|
+
`$XDG_STATE_HOME/code2okf/sessions`, so sessions survive `sbx rm` and retain Pi's
|
|
206
|
+
native per-working-directory layout. All code2okf clones using the same state
|
|
207
|
+
home intentionally share this directory; Pi's own layout separates their
|
|
208
|
+
working directories.
|
|
209
|
+
|
|
210
|
+
State location follows this precedence: an exported absolute `XDG_STATE_HOME`,
|
|
211
|
+
then `~/.local/state`. XDG requires an absolute path, so a relative value counts
|
|
212
|
+
as unset. Paths containing spaces are supported.
|
|
213
|
+
|
|
214
|
+
The state location and the mounts are fixed when a sandbox is created. `code2okf`
|
|
215
|
+
records what it built — the sandbox's identity and the configuration
|
|
216
|
+
fingerprint — *under that state root*, and reuses the sandbox only when the
|
|
217
|
+
recorded identity, the fingerprint and a cheap in-VM probe all agree. Edit the
|
|
218
|
+
kit, or change anything else the fingerprint covers, and the next run rebuilds
|
|
219
|
+
by itself.
|
|
220
|
+
|
|
221
|
+
Changing `XDG_STATE_HOME` is the exception, because it moves the record out of
|
|
222
|
+
view: the new state root has no marker, so a sandbox still named `code2okf`
|
|
223
|
+
cannot be proved to be ours. `code2okf` stops with exit 2 rather than deleting
|
|
224
|
+
something it may not own, and `--fresh` does not override that — it recreates a
|
|
225
|
+
sandbox we *can* prove is ours. Run `sbx rm --force code2okf` yourself, then use
|
|
226
|
+
the new state home.
|
|
227
|
+
|
|
228
|
+
## How it works
|
|
229
|
+
|
|
230
|
+
`code2okf` runs on the host and drives the agent inside a microVM, repeatedly,
|
|
231
|
+
until a hash of the output stops moving. The host drives; everything else
|
|
232
|
+
happens inside the sandbox.
|
|
233
|
+
|
|
234
|
+
One sandbox named `code2okf` serves every run. Rather than mounting your folders
|
|
235
|
+
— sbx fixes a sandbox's mounts when it is created, so a second `-o` would mean
|
|
236
|
+
either a rebuild or writing into the first wiki — the command stages each run
|
|
237
|
+
through a fixed workbench under `$XDG_STATE_HOME/code2okf/work`: your inputs are
|
|
238
|
+
copied in, the target wiki is mirrored in before the run and back out after
|
|
239
|
+
every iteration, and the mount paths never change. The sandbox is rebuilt only
|
|
240
|
+
when the kit it was built from changes, when the configuration no longer
|
|
241
|
+
matches, or on `--fresh`.
|
|
242
|
+
|
|
243
|
+
It runs the agent once per document, re-running the same document (a *Ralph
|
|
244
|
+
loop*) until `merkleokf --nolog -L 0` reports an unchanged wiki root hash.
|
|
245
|
+
`merkleokf` prints a Merkle hash tree, one hash per file and per directory, so a
|
|
246
|
+
change to any page moves the root hash and an unchanged root means the run added
|
|
247
|
+
nothing — which on a first pass is the idempotent re-run, not a failure. The
|
|
248
|
+
loop is capped by `-n` (default 10). The agent's only writable content output is
|
|
249
|
+
`okf/`, the [okfctl](https://github.com/cwest/okfctl) check must pass before it
|
|
250
|
+
finishes, and `SPEC.md` outranks every instruction file. Each run streams
|
|
251
|
+
tool names and assistant text as it goes, and Pi writes its session transcript
|
|
252
|
+
through its native session path into persistent host state.
|
|
253
|
+
|
|
254
|
+
### What the sandbox can reach
|
|
255
|
+
|
|
256
|
+
The sandbox does not get the repository, and it does not get your folders
|
|
257
|
+
either. It gets five named mounts, all of them inside the workbench, and
|
|
258
|
+
nothing else of yours is visible inside the microVM — not `.git`, not the
|
|
259
|
+
`Makefile`, not the kit that built it:
|
|
260
|
+
|
|
261
|
+
| Mount | Access | Why |
|
|
262
|
+
| --- | --- | --- |
|
|
263
|
+
| `work/okf` | read-write | the wiki, and the agent's working directory |
|
|
264
|
+
| `work/md` | read-only | the staged source documents, read as data and never modified |
|
|
265
|
+
| `work/scripts` | read-only | the four helper CLI projects the agent runs |
|
|
266
|
+
| `work/SPEC.md` | read-only | the specification that outranks every instruction |
|
|
267
|
+
| `$XDG_STATE_HOME/code2okf/sessions` | read-write | persistent Pi session state |
|
|
268
|
+
|
|
269
|
+
Every one of them is under `$XDG_STATE_HOME/code2okf`, so the agent never sees a
|
|
270
|
+
path of yours: it works on the staged copies, and the driver mirrors the wiki
|
|
271
|
+
back out. The state *root* is deliberately not mounted — it also holds the
|
|
272
|
+
host-side ownership marker — and no read-write mount is an ancestor of a
|
|
273
|
+
read-only one, so `work/md` and `work/SPEC.md` stay read-only even against root
|
|
274
|
+
in the guest. The mount list lives in one place,
|
|
275
|
+
[`src/code2okf/workbench.py`](src/code2okf/workbench.py); `sbx inspect code2okf` shows
|
|
276
|
+
what a running sandbox actually got. Because `work/okf` is the primary mount it
|
|
277
|
+
is also the working directory inside the VM, which is why the agent addresses
|
|
278
|
+
its siblings as `../md/`, `../scripts/` and `../SPEC.md`.
|
|
279
|
+
|
|
280
|
+
### Repository layout
|
|
281
|
+
|
|
282
|
+
| Path | Description |
|
|
283
|
+
| --- | --- |
|
|
284
|
+
| `md/` | source documents, one agent run each |
|
|
285
|
+
| `okf/` | the generated wiki, `-o`'s default |
|
|
286
|
+
| `src/code2okf/` | the `code2okf` command: workbench, sbx seam, Ralph loop |
|
|
287
|
+
| `Makefile` | the developer tasks — lint, validate, tests, installs |
|
|
288
|
+
| `scripts/` | the four helper CLIs the agent runs (`inspectmd`, `inspectokf`, `sizeokf`, `merkleokf`), plus repository chores |
|
|
289
|
+
| `kits/code2okf/` | what the driver runs: the Docker Sandbox kit and the config it carries |
|
|
290
|
+
| `SPEC.md` | the [OKF specification](https://github.com/GoogleCloudPlatform/open-knowledge-format) the wiki is built against — vendored verbatim, Apache-2.0, see [NOTICE-OKF-SPEC.md](NOTICE-OKF-SPEC.md) |
|
|
291
|
+
| `AGENTS.md` | instructions for coding agents working *on this repo*, not for Pi |
|
|
292
|
+
| `pdf2md/` | optional: converts a PDF into `md` |
|
|
293
|
+
| `web2md/` | optional: scrapes a documentation site into `md` |
|
|
294
|
+
|
|
295
|
+
## What lands in okf/
|
|
296
|
+
|
|
297
|
+
```text
|
|
298
|
+
okf/
|
|
299
|
+
├── index.md # root index, the only one carrying frontmatter
|
|
300
|
+
├── log.md # what each run changed, newest first
|
|
301
|
+
├── <page>.md # a content page at the wiki root
|
|
302
|
+
└── <topic>/ # one directory per topic, nested as deep as it needs
|
|
303
|
+
├── index.md # a plain link list for this directory
|
|
304
|
+
└── <page>.md # a content page within the topic
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Content pages carry `type`, `title`, `description` and `tags` in their
|
|
308
|
+
frontmatter. Slugs are kebab-case. Links are bundle-absolute, so
|
|
309
|
+
`/glossary/verb.md` rather than `glossary/verb.md`. The root `index.md` names
|
|
310
|
+
the spec version the agent reads. Pages are updated in place, not duplicated, so
|
|
311
|
+
compiling the same document twice is safe.
|
|
312
|
+
|
|
313
|
+
## Getting Markdown in
|
|
314
|
+
|
|
315
|
+
`md/` wants clean, structured Markdown, and a source document is rarely that.
|
|
316
|
+
Two helpers produce it. Both are optional, and neither is part of a compile.
|
|
317
|
+
|
|
318
|
+
**From a PDF.** `marker` converts one with the help of a language model, either
|
|
319
|
+
a local Ollama model or a cloud model through OpenRouter. Expect to check the
|
|
320
|
+
output, and run the step by hand — see
|
|
321
|
+
[the pdf2md guide](pdf2md/README.md).
|
|
322
|
+
|
|
323
|
+
**From a website.** `make scrape` walks a documentation site and writes one
|
|
324
|
+
Markdown document into `md/`. No model is involved, so the result is
|
|
325
|
+
deterministic, and the fetched HTML is cached — see
|
|
326
|
+
[the web2md guide](web2md/README.md).
|
|
327
|
+
|
|
328
|
+
## Set up the OpenRouter key
|
|
329
|
+
|
|
330
|
+
`sbx` keeps the key out of the virtual machine. It holds the real string on the
|
|
331
|
+
host and swaps it into requests at its proxy, so inside the sandbox
|
|
332
|
+
`$OPENROUTER_API_KEY` reads `proxy-managed`. Set it twice:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
export OPENROUTER_API_KEY=sk-or-...
|
|
336
|
+
echo "$OPENROUTER_API_KEY" | sbx secret set openrouter
|
|
337
|
+
|
|
338
|
+
# And again as a custom secret, to work around a known sbx issue:
|
|
339
|
+
# https://github.com/docker/sbx-releases/issues/25
|
|
340
|
+
sbx secret set-custom --sandbox code2okf \
|
|
341
|
+
--host openrouter.ai \
|
|
342
|
+
--env OPENROUTER_API_KEY \
|
|
343
|
+
--value "$OPENROUTER_API_KEY"
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
`code2okf` is the kit's name, which comes from `kits/code2okf/spec.yaml`. The
|
|
347
|
+
command reads the key from `sbx secret`, never from your shell environment, and
|
|
348
|
+
refuses to start if it is not proxy-managed. To point the
|
|
349
|
+
agent at a different provider, see [the kit guide](kits/code2okf/README.md).
|
|
350
|
+
|
|
351
|
+
## Troubleshooting
|
|
352
|
+
|
|
353
|
+
**`sbx` reports unknown fields from `kits/code2okf/spec.yaml`.** Your sbx is older
|
|
354
|
+
than 0.43.0 and does not know the kit-spec v2 grammar. Run `brew upgrade sbx`.
|
|
355
|
+
|
|
356
|
+
**A runtime command fails to authenticate.** `code2okf` and `make test-sandbox`
|
|
357
|
+
need an active `sbx login` session.
|
|
358
|
+
|
|
359
|
+
**`hit 10 iterations without converging`.** The wiki root hash kept changing.
|
|
360
|
+
Raise the cap for one run with `code2okf -n 20 …`, or inspect
|
|
361
|
+
`$XDG_STATE_HOME/code2okf/sessions` to see what the agent was doing (by default,
|
|
362
|
+
`~/.local/state/code2okf/sessions`).
|
|
363
|
+
|
|
364
|
+
**`a sandbox called 'code2okf' exists but is not recognisably ours`.** Most often
|
|
365
|
+
you changed `XDG_STATE_HOME` since the sandbox was built, so the ownership
|
|
366
|
+
record it left behind is under the old state root. It can also mean something
|
|
367
|
+
else created it — an older release, or a manual `sbx run`. Either way `code2okf`
|
|
368
|
+
will not delete a sandbox it cannot prove it owns, and `--fresh` will not either:
|
|
369
|
+
run `sbx rm --force code2okf` yourself and try again.
|
|
370
|
+
|
|
371
|
+
**Checking a wiki outside this repository.** The frontmatter guard reads the
|
|
372
|
+
spec as a sibling of the bundle, so `check-okf.sh /some/wiki` needs `SPEC_MD`
|
|
373
|
+
pointed at a copy of [`SPEC.md`](SPEC.md).
|
|
374
|
+
|
|
375
|
+
## Development
|
|
376
|
+
|
|
377
|
+
Lint, tests, the sandbox checks, the helper CLIs and the per-subproject layout
|
|
378
|
+
are covered in [the contributing guide](CONTRIBUTING.md). The short version:
|
|
379
|
+
`make lint` checks the source tree, `make validate` checks the sandbox kit spec,
|
|
380
|
+
and CI runs both on every pull request. `uv run code2okf` runs the command from a
|
|
381
|
+
clone without installing it, `make install` puts it on your PATH, and
|
|
382
|
+
`make install-clis` does the same for the four helper CLIs.
|
|
383
|
+
|
|
384
|
+
## Getting help
|
|
385
|
+
|
|
386
|
+
Questions, bugs and feature requests belong in [the issue
|
|
387
|
+
tracker](https://github.com/lars20070/code2okf/issues).
|
|
388
|
+
|
|
389
|
+
## License
|
|
390
|
+
|
|
391
|
+
Released under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
code2okf/__init__.py,sha256=hR_i0IqSJaomTiNyGGplOsvcX9UcHGBfUJaDVdbKXMU,243
|
|
2
|
+
code2okf/cli.py,sha256=ayurAgqgwPtqdCt-2cAOGzYTcagRI4THIrYuzp2lD68,8849
|
|
3
|
+
code2okf/compile.py,sha256=pS1Jz9dlIvTJ0hBDsT8C_7yR2gmXOJP-hfdFB6AFUts,10869
|
|
4
|
+
code2okf/events.py,sha256=5vNjv9xCZYqQur3ws8XAJ5nJSRego7TLdaO9cxfLlfM,3131
|
|
5
|
+
code2okf/resources.py,sha256=MSQUayXy4B5vxGrwbuOiUQuU4fs99_0x9jKyEqkWtZ4,2994
|
|
6
|
+
code2okf/sandbox.py,sha256=TLAu7M1jCxQhBA0NMtnRt6rH4SGfwQocUQ6ZaNFP5hc,10483
|
|
7
|
+
code2okf/workbench.py,sha256=FiIbg8WuxYV2JVqd3q6GMR4TWqMhScAEFdJtgjNGsY4,22099
|
|
8
|
+
code2okf/SPEC.md,sha256=JqpdoCkniTn5FOV4EHJC2WB9Ty3F_hUycrgvntEDAQE,37748
|
|
9
|
+
code2okf/kit/README.md,sha256=3AyeCiacXjJJNNr-S55mJjjhS0obdW9Y95M5wfxOiOU,5980
|
|
10
|
+
code2okf/kit/spec.yaml,sha256=dUSoFHZFt6CaCrArc3qF6EvUcIwO0Z24W7Xqwy2mRM8,11805
|
|
11
|
+
code2okf/kit/files/home/.local/lib/code2okf/mount-state.sh,sha256=cnWEn4BPZ-qTHtgB-Pulx74Rp2gl-zwupLroAVIyM4o,1485
|
|
12
|
+
code2okf/kit/files/home/.pi/agent/AGENTS.md,sha256=El8afeIK-9uo5z4rXF03RR_3l3NkdI0ZW7AkP--0kG8,8053
|
|
13
|
+
code2okf/kit/files/home/.pi/agent/models.json,sha256=8pGIf4Y118-EeofXqed_RVJOzZd48FkKm3T4Z38bblI,1993
|
|
14
|
+
code2okf/kit/files/home/.pi/agent/settings.json,sha256=-8cblIktm15Q7adpalVqllP7QUmSJGXDfZvWqYAYsKw,138
|
|
15
|
+
code2okf/kit/files/home/.pi/agent/skills/compile-okf/SKILL.md,sha256=dh8ASquJq6iG8OZ_JSr2xk0SrNehTTOjaL8il9wskts,7134
|
|
16
|
+
code2okf/kit/files/home/.pi/agent/skills/compile-okf/scripts/check-okf.sh,sha256=Q5C7_FL4Gwytd1ifR6NnG95AuMhZ_zg5NX06uPva2w8,5425
|
|
17
|
+
code2okf/kit/files/home/.pi/agent/skills/compile-okf/scripts/frontmatter-guard.py,sha256=-xbNadJ4ePM5c2Dl7qttkt_rfvOJMY24xY9k02BzMug,10842
|
|
18
|
+
code2okf/kit/files/home/.pi/agent/skills/curate-okf/SKILL.md,sha256=WF_oLl6yuajWD-3zkV9o4v6vtW4oBky2u8rqRKgpN7Q,3367
|
|
19
|
+
code2okf/kit/files/home/.pi/agent/skills/inspect-md/SKILL.md,sha256=Ra_xL3x-1TDTR3YN70GsCFe1jHeMNS7OQ2qSWlA7IGw,1869
|
|
20
|
+
code2okf/kit/files/home/.pi/agent/skills/inspect-okf/SKILL.md,sha256=VBf-BAmAXypGAKBmNYml-6GZVYqdKM04UgLFOB5ihVo,1885
|
|
21
|
+
code2okf/kit/files/home/.pi/agent/skills/merkle-okf/SKILL.md,sha256=a_gMlO1BpcXyxreLclwTFZ2icRXOMt680b9j0K2_CCg,2312
|
|
22
|
+
code2okf/kit/files/home/.pi/agent/skills/size-okf/SKILL.md,sha256=TfD45rcYDbzNOJ17ES-wjwgysdc_NYXTfMFuJXz2DkA,2003
|
|
23
|
+
code2okf/clis/inspectmd/pyproject.toml,sha256=uym6QUflGRULE3NTcQ6xzEkdI3n6eS4GLEVsReugJb8,1135
|
|
24
|
+
code2okf/clis/inspectmd/src/inspectmd/__init__.py,sha256=jkrG02iA8NPu_xINfOhYqnNbjZnYa-eg8lkPQ4UXA0g,224
|
|
25
|
+
code2okf/clis/inspectmd/src/inspectmd/__main__.py,sha256=VDUxXK2bYv3xcFLn8_xMpGGQYddy9Awfrb6nWolWPeU,93
|
|
26
|
+
code2okf/clis/inspectmd/src/inspectmd/cli.py,sha256=_ek8OziAwPltvV7OtqOVNiM75RIWcEN2d85xpYBahQI,5019
|
|
27
|
+
code2okf/clis/inspectmd/src/inspectmd/parse.py,sha256=8gzA8m3j7QhKXp44nO9LLIEf8Mu_pIDesznFWNIx2dw,6974
|
|
28
|
+
code2okf/clis/inspectokf/pyproject.toml,sha256=BB-x5pUigRzmuThHNNvRsnDa_d7zGg-GraznLf1JrZ8,1126
|
|
29
|
+
code2okf/clis/inspectokf/src/inspectokf/__init__.py,sha256=tI-ZS-a1i7e4Sfc_UoGyFDH0GNHYa6lRiQZcZExb83U,225
|
|
30
|
+
code2okf/clis/inspectokf/src/inspectokf/__main__.py,sha256=nlJVKfGIX3BJ7DaGRqXt9rYEfcJb7Cc69PiPfa34LaE,95
|
|
31
|
+
code2okf/clis/inspectokf/src/inspectokf/cli.py,sha256=hYrTW3jONcgmETqg9HvGS0XaiN_kbjjPOGpYmsh4kec,3174
|
|
32
|
+
code2okf/clis/merkleokf/pyproject.toml,sha256=Np10nGGnOMTc5mBk84GzztvyeooWuf0JDeEyRC0-Fn8,1122
|
|
33
|
+
code2okf/clis/merkleokf/src/merkleokf/__init__.py,sha256=xBRHjO4KZ5FiQBU509MeQ1scNJvVtS3iTZPf5uUDfuI,237
|
|
34
|
+
code2okf/clis/merkleokf/src/merkleokf/__main__.py,sha256=M0wRKwGNKvOn9ZtVgNwkJNhUvbX9uaRa5X1Qd95hMkI,93
|
|
35
|
+
code2okf/clis/merkleokf/src/merkleokf/cli.py,sha256=XlbyMyb4pues-13_B2fPABNWY47MvJ67n-Kt7BA_q1E,3678
|
|
36
|
+
code2okf/clis/merkleokf/src/merkleokf/merkle.py,sha256=6uu3oxUNhMIjkgZVIHzrx6kh7Da44X3ljx37Tl_PII4,5325
|
|
37
|
+
code2okf/clis/sizeokf/pyproject.toml,sha256=NAnVuYXjLmIJTRe61xGelAR14DUCU_HlnOn9CFdxwEU,1119
|
|
38
|
+
code2okf/clis/sizeokf/src/sizeokf/__init__.py,sha256=J48fUfv-vrkQpGiH5fh81HEcFuGGJm-MOXr6Dcsh31w,223
|
|
39
|
+
code2okf/clis/sizeokf/src/sizeokf/__main__.py,sha256=_7fnMHAQcSQuFOXFlGvad4cw58AL3hxTw-YudLuZn3g,89
|
|
40
|
+
code2okf/clis/sizeokf/src/sizeokf/cli.py,sha256=t3rBYhANLcbpNrra86Mj3rmlupvLwRe43IAsvvMk0sg,2836
|
|
41
|
+
code2okf/clis/sizeokf/src/sizeokf/sizes.py,sha256=EhZt1odTPWXRalOk9iyYSGwUVn6k7aLiuPOvvMkKsiE,5825
|
|
42
|
+
code2okf-0.1.0.dist-info/METADATA,sha256=jbMa8UWR3mPYsZdM8YA-nN4mnL4oaBzk9pSisRhGqz8,17484
|
|
43
|
+
code2okf-0.1.0.dist-info/WHEEL,sha256=THafob7ofN-NsuMN7Mg4qZyHaQI7KkD-QlcQatYhXPo,87
|
|
44
|
+
code2okf-0.1.0.dist-info/entry_points.txt,sha256=7-PGhxZn9accvTxDuSyBpiFQb0PI64L-zLszLavM4V8,47
|
|
45
|
+
code2okf-0.1.0.dist-info/licenses/LICENSE,sha256=BdYj-fFskf7Fh84d-L7C8NR75QZf3G-Ad4AoZseySto,1067
|
|
46
|
+
code2okf-0.1.0.dist-info/licenses/LICENSE-OKF-SPEC.txt,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
|
|
47
|
+
code2okf-0.1.0.dist-info/licenses/NOTICE-OKF-SPEC.md,sha256=GKv5Hxz8ypigiDv5GCdhMiGaIPt5WIWKi1BIkfZFNSM,1685
|
|
48
|
+
code2okf-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lars Nilse
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|