diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3cbddbe7..54237c77 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,18 @@ jobs: env: RUSTDOCFLAGS: "-D warnings" + # OKF v0.2 conformance of the knowledge bundle. okf-lint enforces the + # spec; check_okf.py enforces the bundle-local conventions it does not + # cover. See knowledge/knowledge-contract.md for why both run. + # Keep the version and --max-line-length in lockstep with the justfile. + - name: Install okf-lint + run: cargo install okf-lint --version 0.1.1 --locked + + - name: Check knowledge bundle (OKF) + run: | + python3 scripts/check_okf.py knowledge + okf-lint knowledge --max-line-length 10000 + wasm: # std::time panics on wasm32-unknown-unknown, so bashkit routes clock reads # through src/time_compat.rs (web-time on wasm32). This job keeps the crate diff --git a/AGENTS.md b/AGENTS.md index 651b0b3a..9ff09f9b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,10 +19,11 @@ Fix root cause. Unsure: read more code; if stuck, ask w/ short options. Unrecogn ### Knowledge -`knowledge/` is the canonical OKF bundle and persistent project memory. Read relevant knowledge before changing behavior, and update it in the same change when decisions, behavior, constraints, threats, tests, or operations change. New durable engineering knowledge belongs there; see `knowledge/index.md` for the maintenance contract. +`knowledge/` is the canonical OKF bundle and persistent project memory. Read relevant knowledge before changing behavior, and update it in the same change when decisions, behavior, constraints, threats, tests, or operations change. New durable engineering knowledge belongs there; see `knowledge/knowledge-contract.md` for the maintenance contract and the OKF v0.2 rules (`just check-okf` enforces them). | Knowledge | Description | |------|-------------| +| knowledge-contract | Knowledge maintenance rules + OKF v0.2 conformance rules | | architecture | Core interpreter architecture, module structure | | parser | Bash syntax parser design | | vfs | Virtual filesystem abstraction | diff --git a/justfile b/justfile index 7dc426e0..6dd53fa6 100644 --- a/justfile +++ b/justfile @@ -2,6 +2,12 @@ # Install just: ./init-cloud-env.sh (pre-built) or cargo install just # Usage: just (or: just --list) +# Upstream OKF spec linter, pinned. Keep in lockstep with .github/workflows/ci.yml. +okf_lint_version := "0.1.1" + +# Knowledge docs wrap prose at author discretion, so the line-length rule is off. +okf_lint_max_line_length := "10000" + # Default: show available commands default: @just --list @@ -38,6 +44,26 @@ check: cargo clippy --all-targets -- -D warnings cargo test python3 -m unittest discover -s scripts/tests -p 'test_*.py' + just check-okf + +# okf-lint covers the spec rules; check_okf.py covers the bundle-local +# conventions it does not enforce (see knowledge/knowledge-contract.md). +# okf-lint is pinned in CI and skipped here when absent: just install-okf-lint +# Validate the knowledge/ OKF v0.2 bundle +check-okf: + #!/usr/bin/env bash + set -euo pipefail + python3 scripts/check_okf.py knowledge + if command -v okf-lint >/dev/null; then + okf-lint knowledge --max-line-length {{ okf_lint_max_line_length }} + echo "okf-lint {{ okf_lint_version }}: knowledge conforms to OKF v0.2" + else + echo "okf-lint not installed — skipping (just install-okf-lint)" + fi + +# Install the pinned upstream OKF spec linter +install-okf-lint: + cargo install okf-lint --version {{ okf_lint_version }} --locked # Lint and format-check Python bindings python-lint: diff --git a/knowledge/architecture.md b/knowledge/architecture.md index fe0e7db3..a48cc509 100644 --- a/knowledge/architecture.md +++ b/knowledge/architecture.md @@ -1,6 +1,11 @@ --- +type: Architecture title: Bashkit Architecture -summary: Core interpreter architecture, module boundaries, execution flow, and design principles. +description: Core interpreter architecture, module boundaries, execution flow, and design principles. +tags: + - bashkit + - architecture + - interpreter --- # Architecture diff --git a/knowledge/browser-package.md b/knowledge/browser-package.md index 73b78bd6..af5e2b53 100644 --- a/knowledge/browser-package.md +++ b/knowledge/browser-package.md @@ -1,6 +1,12 @@ --- +type: Package Design title: Browser Package -summary: Slim single-threaded WebAssembly package design for browsers and JavaScript runtimes. +description: Slim single-threaded WebAssembly package design for browsers and JavaScript runtimes. +tags: + - bashkit + - wasm + - packaging + - npm --- # WebAssembly Package (`@everruns/bashkit-wasm`) diff --git a/knowledge/builtins.md b/knowledge/builtins.md index e0f8daba..9e13a697 100644 --- a/knowledge/builtins.md +++ b/knowledge/builtins.md @@ -1,6 +1,10 @@ --- +type: Subsystem Design title: Builtin Commands -summary: Builtin command trait, execution planning, registration, and implementation conventions. +description: Builtin command trait, execution planning, registration, and implementation conventions. +tags: + - bashkit + - builtins --- # Builtin Commands diff --git a/knowledge/coreutils-args-port.md b/knowledge/coreutils-args-port.md index aee84028..60cb9a72 100644 --- a/knowledge/coreutils-args-port.md +++ b/knowledge/coreutils-args-port.md @@ -1,6 +1,11 @@ --- +type: Subsystem Design title: Coreutils Argument Port -summary: Code generation design for porting uutils clap arguments and uucore modules. +description: Code generation design for porting uutils clap arguments and uucore modules. +tags: + - bashkit + - builtins + - codegen --- # Coreutils argument-surface port diff --git a/knowledge/credential-injection.md b/knowledge/credential-injection.md index 6b179e9b..0bbb25a9 100644 --- a/knowledge/credential-injection.md +++ b/knowledge/credential-injection.md @@ -1,6 +1,12 @@ --- +type: Subsystem Design title: Credential Injection -summary: Per-host HTTP credential injection without exposing secret values to sandboxed scripts. +description: Per-host HTTP credential injection without exposing secret values to sandboxed scripts. +tags: + - bashkit + - security + - http + - secrets --- # Generic Credential Injection diff --git a/knowledge/documentation.md b/knowledge/documentation.md index 02016814..504509ff 100644 --- a/knowledge/documentation.md +++ b/knowledge/documentation.md @@ -1,6 +1,10 @@ --- +type: Playbook title: Documentation Architecture -summary: User documentation and Rustdoc guide organization, embedding, and maintenance. +description: User documentation and Rustdoc guide organization, embedding, and maintenance. +tags: + - bashkit + - documentation --- # Documentation Approach diff --git a/knowledge/emscripten-wheels.md b/knowledge/emscripten-wheels.md index ff379246..4f94cb54 100644 --- a/knowledge/emscripten-wheels.md +++ b/knowledge/emscripten-wheels.md @@ -1,6 +1,12 @@ --- +type: Package Design title: Emscripten Wheels -summary: Reduced-feature Pyodide and Emscripten Python wheel design and build constraints. +description: Reduced-feature Pyodide and Emscripten Python wheel design and build constraints. +tags: + - bashkit + - python + - packaging + - wasm --- # Emscripten / Pyodide Wheels diff --git a/knowledge/eval.md b/knowledge/eval.md index 7703a12d..4bcd1513 100644 --- a/knowledge/eval.md +++ b/knowledge/eval.md @@ -1,6 +1,11 @@ --- +type: Subsystem Design title: Evaluation Framework -summary: LLM evaluation study design, dataset format, execution, and scoring. +description: LLM evaluation study design, dataset format, execution, and scoring. +tags: + - bashkit + - eval + - llm --- # bashkit-eval: mira Eval Study diff --git a/knowledge/git-support.md b/knowledge/git-support.md index 0b9e0103..a2c4cfe5 100644 --- a/knowledge/git-support.md +++ b/knowledge/git-support.md @@ -1,6 +1,11 @@ --- +type: Subsystem Design title: Git Support -summary: Sandboxed Git operations over the virtual filesystem. +description: Sandboxed Git operations over the virtual filesystem. +tags: + - bashkit + - git + - sandbox --- # Git Support diff --git a/knowledge/http-transport.md b/knowledge/http-transport.md index fd565ddd..5597a824 100644 --- a/knowledge/http-transport.md +++ b/knowledge/http-transport.md @@ -1,6 +1,12 @@ --- +type: Subsystem Design title: HTTP Transport -summary: Pluggable host-controlled HTTP transport for curl and wget. +description: Pluggable host-controlled HTTP transport for curl and wget. +tags: + - bashkit + - http + - network + - embedding --- # Pluggable HTTP Transport diff --git a/knowledge/index.md b/knowledge/index.md index 1f64f5c5..4395f576 100644 --- a/knowledge/index.md +++ b/knowledge/index.md @@ -1,39 +1,56 @@ --- -title: Bashkit Knowledge -summary: Persistent, agent-maintained product and engineering knowledge for Bashkit. -tags: - - bashkit - - engineering - - product - - security - - operations +okf_version: "0.2" --- # Bashkit Knowledge -This directory is Bashkit's canonical [Open Knowledge Format (OKF)](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) bundle and persistent project memory. +* [Knowledge Maintenance Contract](knowledge-contract.md) - Rules for maintaining the Bashkit knowledge bundle and its OKF conformance. +* [Update Log](log.md) - Chronological history of changes to this bundle. -## Contents +# Foundations -The documents record architecture, behavior, constraints, security decisions, testing strategy, release procedures, and intentional limitations. Generated factual inventories live under [`status/`](status/). +* [Bashkit Architecture](architecture.md) - Core interpreter architecture, module boundaries, execution flow, and design principles. +* [Parser](parser.md) - Bash syntax parser and lexer architecture and compatibility decisions. +* [Virtual Filesystem](vfs.md) - Filesystem abstraction, path safety, implementations, and sandbox invariants. +* [Builtin Commands](builtins.md) - Builtin command trait, execution planning, registration, and implementation conventions. +* [Parallel Execution](parallel-execution.md) - Threading model, shared ownership, and concurrency safety requirements. -## Maintenance contract +# Security -- Treat this knowledge as part of the implementation, not as historical documentation. -- Before changing behavior, read the relevant knowledge documents and follow their decisions or update them in the same change. -- When code changes a documented behavior, design decision, invariant, limitation, threat, test strategy, operational process, or generated fact, update the affected knowledge in the same pull request. -- Record important decisions that are not recoverable from code. Prefer links to source and tests over duplicating volatile implementation details. -- Keep stable identifiers such as `TM-*` and `L-*`; never renumber them. -- Add new durable project knowledge here. User-facing guides remain in `docs/`; embedded Rust guides remain in `crates/bashkit/docs/`. -- Every knowledge subdirectory must contain an OKF `index.md` with `title` and `summary` frontmatter. -- Run the relevant drift checks and tests after updating generated or machine-validated knowledge. +* [Threat Model](threat-model.md) - Bashkit assets, trust boundaries, threats, mitigations, and stable threat identifiers. +* [Security Testing](security-testing.md) - Fail-point injection and layered security regression testing strategy. +* [Credential Injection](credential-injection.md) - Per-host HTTP credential injection without exposing secret values to sandboxed scripts. +* [Request Signing](request-signing.md) - Transparent Ed25519 HTTP message signing according to RFC 9421. +* [HTTP Transport](http-transport.md) - Pluggable host-controlled HTTP transport for curl and wget. -## Knowledge map +# Runtimes and packages -| Area | Documents | -|---|---| -| Foundations | [Architecture](architecture.md), [parser](parser.md), [virtual filesystem](vfs.md), [builtins](builtins.md), [parallel execution](parallel-execution.md) | -| Security | [Threat model](threat-model.md), [security testing](security-testing.md), [credential injection](credential-injection.md), [request signing](request-signing.md), [HTTP transport](http-transport.md) | -| Runtimes and packages | [Python builtin](python-builtin.md), [TypeScript runtime](zapcode-runtime.md), [SQLite builtin](sqlite-builtin.md), [Python package](python-package.md), [Emscripten wheels](emscripten-wheels.md), [WebAssembly package](browser-package.md) | -| Integrations | [Tool contract](tool-contract.md), [scripted orchestration](scripted-tool-orchestration.md), [Git](git-support.md), [SSH](ssh-support.md) | -| Quality and operations | [Testing](testing.md), [limitations](limitations.md), [documentation](documentation.md), [maintenance](maintenance.md), [release process](release-process.md), [performance results](performance-results.md), [eval](eval.md) | +* [Python Builtin](python-builtin.md) - Embedded Python execution through Monty with security and resource controls. +* [ZapCode Runtime](zapcode-runtime.md) - Embedded TypeScript runtime, external functions, VFS bridging, and resource limits. +* [SQLite Builtin](sqlite-builtin.md) - Embedded SQLite through Turso with memory and virtual filesystem backends. +* [Coreutils Argument Port](coreutils-args-port.md) - Code generation design for porting uutils clap arguments and uucore modules. +* [Python Package](python-package.md) - Python bindings, PyPI wheels, ABI strategy, and platform build matrix. +* [Emscripten Wheels](emscripten-wheels.md) - Reduced-feature Pyodide and Emscripten Python wheel design and build constraints. +* [Browser Package](browser-package.md) - Slim single-threaded WebAssembly package design for browsers and JavaScript runtimes. + +# Integrations + +* [Tool Contract](tool-contract.md) - Public LLM tool trait behavior, schemas, callbacks, and error semantics. +* [Scripted Tool Orchestration](scripted-tool-orchestration.md) - Composition of tool definitions and callbacks into Bash-scripted orchestrators. +* [Git Support](git-support.md) - Sandboxed Git operations over the virtual filesystem. +* [SSH Support](ssh-support.md) - Sandboxed SSH, SCP, and SFTP operations and security boundaries. +* [Interactive Shell](interactive-shell.md) - Interactive REPL design with rustyline-based line editing. + +# Quality and operations + +* [Testing Strategy](testing.md) - Test organization, patterns, fixtures, differential testing, and CI expectations. +* [Known Limitations](limitations.md) - Intentional gaps, partial features, and Bash and POSIX compatibility stance. +* [Documentation Architecture](documentation.md) - User documentation and Rustdoc guide organization, embedding, and maintenance. +* [Maintenance](maintenance.md) - Pre-release dependency, security, compatibility, and artifact maintenance requirements. +* [Release Process](release-process.md) - Versioning, validation, tagging, and publication to crates.io, PyPI, and npm. +* [Performance Results](performance-results.md) - Benchmark harnesses, result locations, naming, and publication contract. +* [Evaluation Framework](eval.md) - LLM evaluation study design, dataset format, execution, and scoring. + +# Subdirectories + +* [status/](status/) - Machine-generated inventories that capture the current Bashkit implementation state. diff --git a/knowledge/interactive-shell.md b/knowledge/interactive-shell.md index 4cba496c..bd0632ca 100644 --- a/knowledge/interactive-shell.md +++ b/knowledge/interactive-shell.md @@ -1,6 +1,11 @@ --- +type: Subsystem Design title: Interactive Shell -summary: Interactive REPL design with rustyline-based line editing. +description: Interactive REPL design with rustyline-based line editing. +tags: + - bashkit + - cli + - repl --- # Interactive Shell Mode diff --git a/knowledge/knowledge-contract.md b/knowledge/knowledge-contract.md new file mode 100644 index 00000000..1937c839 --- /dev/null +++ b/knowledge/knowledge-contract.md @@ -0,0 +1,94 @@ +--- +type: Playbook +title: Knowledge Maintenance Contract +description: Rules for maintaining the Bashkit knowledge bundle and its OKF conformance. +tags: + - bashkit + - knowledge + - okf + - process +--- + +# Knowledge Maintenance Contract + +`knowledge/` is Bashkit's canonical [Open Knowledge Format (OKF) v0.2](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) +bundle and persistent project memory. + +## Maintenance rules + +- Treat this knowledge as part of the implementation, not as historical documentation. +- Before changing behavior, read the relevant knowledge documents and follow their decisions or update them in the same change. +- When code changes a documented behavior, design decision, invariant, limitation, threat, test strategy, operational process, or generated fact, update the affected knowledge in the same pull request. +- Record important decisions that are not recoverable from code. Prefer links to source and tests over duplicating volatile implementation details. +- Keep stable identifiers such as `TM-*` and `L-*`; never renumber them. +- Add new durable project knowledge here. User-facing guides remain in `docs/`; embedded Rust guides remain in `crates/bashkit/docs/`. +- Run the relevant drift checks and tests after updating generated or machine-validated knowledge. + +## OKF conformance rules + +The bundle targets OKF v0.2, declared as `okf_version: "0.2"` in the bundle-root [`index.md`](index.md). + +- Every `.md` file except the reserved `index.md` and `log.md` is a **concept document** and MUST start with a YAML frontmatter block containing a non-empty `type`. +- `title`, `description`, and `tags` are recommended and used throughout this bundle; `description` is a single sentence that index entries reuse verbatim. +- `index.md` files carry **no** frontmatter, except the bundle-root `index.md`, which may carry only `okf_version`. +- `index.md` bodies are link lists grouped under headings: `* [Title](path) - description`. +- `log.md` bodies are date-grouped entries (`## YYYY-MM-DD`), newest first. +- Prose that is not a directory listing belongs in a concept document, not in an `index.md`. + +Type values are producer-defined. This bundle uses: `Architecture`, `Subsystem Design`, +`Interface Contract`, `Package Design`, `Threat Model`, `Test Strategy`, `Limitations`, +`Playbook`, `Generated Inventory`. + +## Enforcement + +`scripts/check_okf.py knowledge` validates the rules above. It runs in the CI lint job, +via `just check-okf`, and from `scripts/tests/test_check_okf.py` (covered by `just check`). + +```console +$ python3 scripts/check_okf.py knowledge +knowledge: OKF v0.2 conformant (31 concepts, 2 index files, 1 log file) +``` + +## Third-party OKF linters (evaluated 2026-07-26) + +Four off-the-shelf implementations were built and run against this bundle and +against a fixture per regression class. All four agree the bundle is conformant; +they differ in how much they enforce. + +| Tool | Language / license | Distribution | Spec | Verdict | +|---|---|---|---|---| +| [`okf-lint`](https://github.com/rpmoore/okf-lint) | Rust, Apache-2.0 | crates.io `0.1.1` | v0.2 | **adopted** | +| [`okftool`](https://github.com/ryansann/okftool) | Rust, Apache-2.0 | source / release binaries | v0.2 | not adopted | +| [`okf`](https://crates.io/crates/okf) | Rust, Apache-2.0 | crates.io `0.1.0-alpha.1` | **v0.1** | not adopted | +| [`okflint`](https://github.com/mattdav/okflint) | Python 3.12+, MIT | PyPI `0.3.1` | manifest-driven | not adopted | + +Regression coverage (fail = caught, pass = slipped through): + +| Regression | `okf` | `okftool` | `okf-lint` | `check_okf.py` | +|---|---|---|---|---| +| Concept missing `type` | fail | fail | fail | fail | +| `summary` instead of `description` | pass | pass | pass | fail | +| Frontmatter on `index.md` | pass | pass | fail | fail | +| Concept absent from `index.md` | pass | pass | pass | fail | +| `log.md` heading not `YYYY-MM-DD` | pass | pass | fail | fail | + +`okf-lint` is the strongest of the four: it is the only one that enforces the +reserved `index.md`/`log.md` structures, it cites the spec section in every +diagnostic, and it installs from crates.io with a pinned version. It runs in CI +and in `just check-okf`, with `--max-line-length 10000` because knowledge docs +wrap prose at author discretion. + +It does not subsume `check_okf.py`. The two rows it lets through — `summary` +instead of `description`, and a concept missing from its `index.md` — are +bundle-local conventions, and the first is exactly the defect the original +migration shipped. Both checks therefore run together. + +The others were rejected on substance, not maturity: `okftool` treats everything +but `type` as advisory (0 errors on all five regressions); `okf` implements OKF +**v0.1**, so it validates this v0.2 bundle against the wrong revision; `okflint` +validates against a hand-authored `okf-base.yaml` rather than the spec, so +adopting it means maintaining the rule set anyway, and it requires Python 3.12+ +against this repository's 3.9 floor. + +`okftool lint` and `okf graph` remain useful ad hoc for advisory graph checks — +both report that most concepts here have no cross-links to each other. diff --git a/knowledge/limitations.md b/knowledge/limitations.md index 90408160..a78ac95f 100644 --- a/knowledge/limitations.md +++ b/knowledge/limitations.md @@ -1,6 +1,11 @@ --- +type: Limitations title: Known Limitations -summary: Intentional gaps, partial features, and Bash and POSIX compatibility stance. +description: Intentional gaps, partial features, and Bash and POSIX compatibility stance. +tags: + - bashkit + - limitations + - compatibility --- # Limitations diff --git a/knowledge/log.md b/knowledge/log.md new file mode 100644 index 00000000..bfd10c13 --- /dev/null +++ b/knowledge/log.md @@ -0,0 +1,11 @@ +# Bashkit Knowledge Update Log + +## 2026-07-26 + +* **Decision**: Evaluated four OKF implementations and adopted [`okf-lint`](https://github.com/rpmoore/okf-lint) as the upstream spec gate alongside `scripts/check_okf.py`, which covers the bundle-local conventions it does not enforce. Rationale and coverage tables in [Knowledge Maintenance Contract](knowledge-contract.md). + +## 2026-07-25 + +* **Conformance**: Made the bundle conform to OKF v0.2 — added the required `type` to every concept, renamed `summary` to `description`, stripped frontmatter from reserved `index.md` files, declared `okf_version: "0.2"` at the bundle root, and added this log. +* **Creation**: Moved the maintenance rules out of `index.md` into [Knowledge Maintenance Contract](knowledge-contract.md), and described the generated builtin inventory in [Builtin Inventory](status/builtin-inventory.md). +* **Migration**: Moved `specs/` to `knowledge/` as the canonical knowledge bundle. diff --git a/knowledge/maintenance.md b/knowledge/maintenance.md index 5a4e12ae..ed5fccc5 100644 --- a/knowledge/maintenance.md +++ b/knowledge/maintenance.md @@ -1,6 +1,11 @@ --- +type: Playbook title: Maintenance -summary: Pre-release dependency, security, compatibility, and artifact maintenance requirements. +description: Pre-release dependency, security, compatibility, and artifact maintenance requirements. +tags: + - bashkit + - maintenance + - operations --- # Pre-Release Maintenance diff --git a/knowledge/parallel-execution.md b/knowledge/parallel-execution.md index 6338f79e..1ec8973b 100644 --- a/knowledge/parallel-execution.md +++ b/knowledge/parallel-execution.md @@ -1,6 +1,11 @@ --- +type: Subsystem Design title: Parallel Execution -summary: Threading model, shared ownership, and concurrency safety requirements. +description: Threading model, shared ownership, and concurrency safety requirements. +tags: + - bashkit + - concurrency + - performance --- # Parallel Execution @@ -39,7 +44,6 @@ fan-out (each its own `Bash`, sharing one `Arc`) actually produces correct per-session output, and that concurrent sessions sharing a filesystem don't cross-contaminate. Run via `just test` (no extra features). - ### Expected Results - Light workload: ~2x parallel speedup diff --git a/knowledge/parser.md b/knowledge/parser.md index d2880707..29090ec4 100644 --- a/knowledge/parser.md +++ b/knowledge/parser.md @@ -1,6 +1,11 @@ --- +type: Subsystem Design title: Parser -summary: Bash syntax parser and lexer architecture and compatibility decisions. +description: Bash syntax parser and lexer architecture and compatibility decisions. +tags: + - bashkit + - parser + - bash --- # Parser Design diff --git a/knowledge/performance-results.md b/knowledge/performance-results.md index 87044d38..e94a9227 100644 --- a/knowledge/performance-results.md +++ b/knowledge/performance-results.md @@ -1,6 +1,11 @@ --- +type: Playbook title: Performance Results -summary: Benchmark harnesses, result locations, naming, and publication contract. +description: Benchmark harnesses, result locations, naming, and publication contract. +tags: + - bashkit + - benchmarks + - performance --- # Performance Results and Site Aggregation diff --git a/knowledge/python-builtin.md b/knowledge/python-builtin.md index 25cb75dc..8d342769 100644 --- a/knowledge/python-builtin.md +++ b/knowledge/python-builtin.md @@ -1,6 +1,12 @@ --- +type: Subsystem Design title: Python Builtin -summary: Embedded Python execution through Monty with security and resource controls. +description: Embedded Python execution through Monty with security and resource controls. +tags: + - bashkit + - python + - runtime + - sandbox --- # Python Builtin (Monty) diff --git a/knowledge/python-package.md b/knowledge/python-package.md index 520b8486..e2f435d6 100644 --- a/knowledge/python-package.md +++ b/knowledge/python-package.md @@ -1,6 +1,12 @@ --- +type: Package Design title: Python Package -summary: Python bindings, PyPI wheels, ABI strategy, and platform build matrix. +description: Python bindings, PyPI wheels, ABI strategy, and platform build matrix. +tags: + - bashkit + - python + - packaging + - pypi --- # Python Package diff --git a/knowledge/release-process.md b/knowledge/release-process.md index 10cf7ad1..c7456707 100644 --- a/knowledge/release-process.md +++ b/knowledge/release-process.md @@ -1,6 +1,11 @@ --- +type: Playbook title: Release Process -summary: Versioning, validation, tagging, and publication to crates.io, PyPI, and npm. +description: Versioning, validation, tagging, and publication to crates.io, PyPI, and npm. +tags: + - bashkit + - release + - operations --- # Release Process diff --git a/knowledge/request-signing.md b/knowledge/request-signing.md index c77c0f67..05ee49ca 100644 --- a/knowledge/request-signing.md +++ b/knowledge/request-signing.md @@ -1,6 +1,12 @@ --- +type: Subsystem Design title: Request Signing -summary: Transparent Ed25519 HTTP message signing according to RFC 9421. +description: Transparent Ed25519 HTTP message signing according to RFC 9421. +tags: + - bashkit + - security + - http + - signing --- # Transparent Request Signing (bot-auth) diff --git a/knowledge/scripted-tool-orchestration.md b/knowledge/scripted-tool-orchestration.md index 9c53096e..6603cf34 100644 --- a/knowledge/scripted-tool-orchestration.md +++ b/knowledge/scripted-tool-orchestration.md @@ -1,6 +1,11 @@ --- +type: Subsystem Design title: Scripted Tool Orchestration -summary: Composition of tool definitions and callbacks into Bash-scripted orchestrators. +description: Composition of tool definitions and callbacks into Bash-scripted orchestrators. +tags: + - bashkit + - tools + - orchestration --- # Scripted Tool Orchestration diff --git a/knowledge/security-testing.md b/knowledge/security-testing.md index 6617cf27..0e395e19 100644 --- a/knowledge/security-testing.md +++ b/knowledge/security-testing.md @@ -1,6 +1,11 @@ --- +type: Test Strategy title: Security Testing -summary: Fail-point injection and layered security regression testing strategy. +description: Fail-point injection and layered security regression testing strategy. +tags: + - bashkit + - testing + - security --- # Security Testing with Fail Points diff --git a/knowledge/sqlite-builtin.md b/knowledge/sqlite-builtin.md index d11803ae..b57c287f 100644 --- a/knowledge/sqlite-builtin.md +++ b/knowledge/sqlite-builtin.md @@ -1,6 +1,11 @@ --- +type: Subsystem Design title: SQLite Builtin -summary: Embedded SQLite through Turso with memory and virtual filesystem backends. +description: Embedded SQLite through Turso with memory and virtual filesystem backends. +tags: + - bashkit + - sqlite + - builtins --- # `sqlite` Builtin diff --git a/knowledge/ssh-support.md b/knowledge/ssh-support.md index 35f45be3..a27951f1 100644 --- a/knowledge/ssh-support.md +++ b/knowledge/ssh-support.md @@ -1,6 +1,12 @@ --- +type: Subsystem Design title: SSH Support -summary: Sandboxed SSH, SCP, and SFTP operations and security boundaries. +description: Sandboxed SSH, SCP, and SFTP operations and security boundaries. +tags: + - bashkit + - ssh + - network + - security --- # SSH Support diff --git a/knowledge/status/builtin-inventory.md b/knowledge/status/builtin-inventory.md new file mode 100644 index 00000000..0c8213d0 --- /dev/null +++ b/knowledge/status/builtin-inventory.md @@ -0,0 +1,28 @@ +--- +type: Generated Inventory +title: Builtin Inventory +description: Generated inventory of Bashkit builtin commands and their flags. +resource: builtins.json +tags: + - bashkit + - builtins + - generated +generated: + by: process:just-regen-builtins +--- + +# Builtin Inventory + +[`builtins.json`](builtins.json) is a generated view of implementation state: the +list of builtin commands the interpreter registers, with their supported flags. + +Do not edit it by hand. Regenerate and commit it with the behavior change that +caused it: + +```console +$ just regen-builtins +``` + +`builtins-drift.yml` fails CI when the committed file no longer matches what the +code registers. Design for the builtins themselves lives in +[builtins](../builtins.md); known gaps in [limitations](../limitations.md). diff --git a/knowledge/status/index.md b/knowledge/status/index.md index 1a61f0d4..592816a0 100644 --- a/knowledge/status/index.md +++ b/knowledge/status/index.md @@ -1,14 +1,3 @@ ---- -title: Generated Status -summary: Machine-generated inventories that capture the current Bashkit implementation state. -tags: - - bashkit - - generated - - status ---- - # Generated Status -Files in this collection are generated views of implementation state. Do not edit generated artifacts by hand; use the repository generator and commit updates with the behavior that caused them. - -- [`builtins.json`](builtins.json) — builtin command inventory; regenerate with `just regen-builtins`. +* [Builtin Inventory](builtin-inventory.md) - Generated inventory of Bashkit builtin commands and their flags. diff --git a/knowledge/testing.md b/knowledge/testing.md index 4a27af7c..0cd34587 100644 --- a/knowledge/testing.md +++ b/knowledge/testing.md @@ -1,6 +1,11 @@ --- +type: Test Strategy title: Testing Strategy -summary: Test organization, patterns, fixtures, differential testing, and CI expectations. +description: Test organization, patterns, fixtures, differential testing, and CI expectations. +tags: + - bashkit + - testing + - ci --- # Testing Strategy diff --git a/knowledge/threat-model.md b/knowledge/threat-model.md index 6d93eae3..31e0cb40 100644 --- a/knowledge/threat-model.md +++ b/knowledge/threat-model.md @@ -1,6 +1,11 @@ --- +type: Threat Model title: Threat Model -summary: Bashkit assets, trust boundaries, threats, mitigations, and stable threat identifiers. +description: Bashkit assets, trust boundaries, threats, mitigations, and stable threat identifiers. +tags: + - bashkit + - security + - threats --- # Bashkit Threat Model diff --git a/knowledge/tool-contract.md b/knowledge/tool-contract.md index d6d13a1c..6b5cc885 100644 --- a/knowledge/tool-contract.md +++ b/knowledge/tool-contract.md @@ -1,6 +1,12 @@ --- +type: Interface Contract title: Tool Contract -summary: Public LLM tool trait behavior, schemas, callbacks, and error semantics. +description: Public LLM tool trait behavior, schemas, callbacks, and error semantics. +tags: + - bashkit + - tools + - llm + - api --- # Tool Contract diff --git a/knowledge/vfs.md b/knowledge/vfs.md index 01fc86cc..0acf4a75 100644 --- a/knowledge/vfs.md +++ b/knowledge/vfs.md @@ -1,6 +1,11 @@ --- +type: Subsystem Design title: Virtual Filesystem -summary: Filesystem abstraction, path safety, implementations, and sandbox invariants. +description: Filesystem abstraction, path safety, implementations, and sandbox invariants. +tags: + - bashkit + - filesystem + - sandbox --- # Virtual Filesystem Design diff --git a/knowledge/zapcode-runtime.md b/knowledge/zapcode-runtime.md index 4a05be26..31ed1972 100644 --- a/knowledge/zapcode-runtime.md +++ b/knowledge/zapcode-runtime.md @@ -1,6 +1,12 @@ --- +type: Subsystem Design title: ZapCode Runtime -summary: Embedded TypeScript runtime, external functions, VFS bridging, and resource limits. +description: Embedded TypeScript runtime, external functions, VFS bridging, and resource limits. +tags: + - bashkit + - typescript + - runtime + - sandbox --- # ZapCode TypeScript Runtime diff --git a/scripts/check_okf.py b/scripts/check_okf.py new file mode 100644 index 00000000..fbe8d089 --- /dev/null +++ b/scripts/check_okf.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python3 +"""Validate an Open Knowledge Format (OKF) v0.2 bundle. + +Spec: https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md + +Conformance rules enforced here (SPEC sections 4, 8, 9, 11, 12): + +* every non-reserved `.md` file has a parseable YAML frontmatter block; +* every such frontmatter carries a non-empty `type`; +* reserved `index.md` carries no frontmatter, except the bundle-root one, + which may carry only `okf_version`; +* reserved `log.md` carries no frontmatter and groups entries under + `## YYYY-MM-DD` headings. + +Bundle-local conventions also checked (see knowledge/knowledge-contract.md): +`title` and `description` are required, `description` is a single line, and +every concept and subdirectory is listed in its directory's `index.md`. + +No third-party dependencies: the frontmatter subset used by this bundle is +parsed directly, so the check runs anywhere `python3` does. +""" + +from __future__ import annotations + +import argparse +import pathlib +import re +import sys + +RESERVED = ("index.md", "log.md") +DATE_HEADING = re.compile(r"^## \d{4}-\d{2}-\d{2}\s*$") +LINK = re.compile(r"\[[^\]]*\]\(([^)]+)\)") + + +def split_frontmatter(text: str) -> tuple[str | None, str]: + """Return (frontmatter, body). Frontmatter is None when absent.""" + if not text.startswith("---\n"): + return None, text + end = text.find("\n---\n", 3) + if end == -1: + raise ValueError("unterminated frontmatter block") + return text[4:end], text[end + 5 :] + + +def parse_frontmatter(fm: str) -> dict[str, object]: + """Parse the flat-scalar + list-of-scalars + one-level-mapping YAML subset.""" + data: dict[str, object] = {} + key: str | None = None + for lineno, raw in enumerate(fm.splitlines(), start=2): + line = raw.rstrip() + if not line or line.lstrip().startswith("#"): + continue + if line.startswith(" "): + if key is None: + raise ValueError(f"line {lineno}: indented entry without a key") + item = line.strip() + if item.startswith("- "): + existing = data.get(key) + items = existing if isinstance(existing, list) else [] + data[key] = items + [item[2:].strip()] + elif ":" in item: + nested = data.get(key) + if not isinstance(nested, dict): + nested = {} + data[key] = nested + sub, _, val = item.partition(":") + nested[sub.strip()] = val.strip() + else: + raise ValueError(f"line {lineno}: unparseable entry {item!r}") + continue + if ":" not in line: + raise ValueError(f"line {lineno}: unparseable key line {line!r}") + key, _, value = line.partition(":") + key = key.strip() + value = value.strip() + data[key] = value if value else "" + return data + + +def index_targets(path: pathlib.Path) -> set[str]: + if not path.exists(): + return set() + _, body = split_frontmatter(path.read_text()) + return {t.split("#", 1)[0].rstrip("/") for t in LINK.findall(body)} + + +def check_concept(path: pathlib.Path, rel: str, errors: list[str]) -> None: + fm_text, _ = split_frontmatter(path.read_text()) + if fm_text is None: + errors.append(f"{rel}: missing YAML frontmatter block") + return + fm = parse_frontmatter(fm_text) + if not fm.get("type"): + errors.append(f"{rel}: frontmatter must contain a non-empty 'type'") + for field in ("title", "description"): + if not fm.get(field): + errors.append(f"{rel}: frontmatter must contain a non-empty '{field}'") + if "summary" in fm: + errors.append(f"{rel}: 'summary' is not an OKF field — use 'description'") + + +def check_index(path: pathlib.Path, rel: str, is_root: bool, errors: list[str]) -> None: + fm_text, body = split_frontmatter(path.read_text()) + if fm_text is not None: + keys = set(parse_frontmatter(fm_text)) + allowed = {"okf_version"} if is_root else set() + extra = sorted(keys - allowed) + if extra: + errors.append( + f"{rel}: index.md may not carry frontmatter keys {extra} " + f"(allowed here: {sorted(allowed) or 'none'})" + ) + if not body.strip(): + errors.append(f"{rel}: index.md body is empty") + + +def check_log(path: pathlib.Path, rel: str, errors: list[str]) -> None: + fm_text, body = split_frontmatter(path.read_text()) + if fm_text is not None: + errors.append(f"{rel}: log.md may not carry frontmatter") + headings = [ln for ln in body.splitlines() if ln.startswith("## ")] + if not headings: + errors.append(f"{rel}: log.md needs at least one '## YYYY-MM-DD' heading") + for heading in headings: + if not DATE_HEADING.match(heading): + errors.append(f"{rel}: log heading {heading!r} is not '## YYYY-MM-DD'") + + +def check_bundle(root: pathlib.Path) -> tuple[list[str], dict[str, int]]: + errors: list[str] = [] + counts = {"concepts": 0, "indexes": 0, "logs": 0} + if not (root / "index.md").exists(): + errors.append("index.md: bundle root index is missing") + + for directory in sorted(p for p in root.rglob("*") if p.is_dir()) + [root]: + listed = index_targets(directory / "index.md") + for child in sorted(directory.iterdir()): + rel = child.relative_to(root).as_posix() + if child.is_dir(): + if not (child / "index.md").exists(): + errors.append(f"{rel}/: subdirectory has no index.md") + if child.name not in listed: + errors.append(f"{rel}/: not listed in {directory.name}/index.md") + continue + if child.suffix != ".md": + continue + if child.name in RESERVED: + continue + if child.name not in listed: + errors.append( + f"{rel}: not listed in " + f"{(directory / 'index.md').relative_to(root).as_posix()}" + ) + + for path in sorted(root.rglob("*.md")): + rel = path.relative_to(root).as_posix() + try: + if path.name == "index.md": + counts["indexes"] += 1 + check_index(path, rel, is_root=path.parent == root, errors=errors) + elif path.name == "log.md": + counts["logs"] += 1 + check_log(path, rel, errors) + else: + counts["concepts"] += 1 + check_concept(path, rel, errors) + except ValueError as exc: + errors.append(f"{rel}: {exc}") + + return errors, counts + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("bundle", nargs="?", default="knowledge", type=pathlib.Path) + args = parser.parse_args(argv) + + root = args.bundle + if not root.is_dir(): + print(f"error: {root} is not a directory", file=sys.stderr) + return 2 + + errors, counts = check_bundle(root) + if errors: + print(f"{root}: {len(errors)} OKF conformance error(s)", file=sys.stderr) + for error in errors: + print(f" {error}", file=sys.stderr) + return 1 + + print( + f"{root}: OKF v0.2 conformant ({counts['concepts']} concepts, " + f"{counts['indexes']} index files, {counts['logs']} log file" + f"{'s' if counts['logs'] != 1 else ''})" + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/tests/test_check_okf.py b/scripts/tests/test_check_okf.py new file mode 100644 index 00000000..21bc325d --- /dev/null +++ b/scripts/tests/test_check_okf.py @@ -0,0 +1,118 @@ +"""Tests for scripts/check_okf.py (OKF v0.2 bundle conformance check). + +One case per rejection class, plus a positive control — without it, a +validator that errored on everything would pass every negative test. +Conformance of the real bundle is covered by `just check-okf` and CI, not +duplicated here. + +unittest.TestCase so `python3 -m unittest discover -s scripts/tests` (wired +into `just check`) actually executes them; pytest runs them too. +""" + +import pathlib +import subprocess +import sys +import tempfile +import unittest + +REPO = pathlib.Path(__file__).resolve().parents[2] +SCRIPT = REPO / "scripts" / "check_okf.py" + +CONCEPT = """\ +--- +type: Subsystem Design +title: Widget +description: One sentence about the widget. +tags: + - bashkit +--- + +# Widget +""" + +ROOT_INDEX = """\ +--- +okf_version: "0.2" +--- + +# Bundle + +* [Widget](widget.md) - One sentence about the widget. +""" + +LOG = """\ +# Bundle Update Log + +## 2026-07-25 +* **Creation**: Added [Widget](widget.md). +""" + + +def run(bundle: pathlib.Path) -> subprocess.CompletedProcess: + return subprocess.run( + [sys.executable, str(SCRIPT), str(bundle)], + capture_output=True, + text=True, + ) + + +class CheckOkfTest(unittest.TestCase): + def setUp(self) -> None: + self._tmp = tempfile.TemporaryDirectory() + self.bundle = pathlib.Path(self._tmp.name) / "bundle" + self.bundle.mkdir() + (self.bundle / "index.md").write_text(ROOT_INDEX) + (self.bundle / "log.md").write_text(LOG) + (self.bundle / "widget.md").write_text(CONCEPT) + self.addCleanup(self._tmp.cleanup) + + def test_conformant_bundle_accepted(self) -> None: + result = run(self.bundle) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertIn("OKF v0.2 conformant", result.stdout) + + def test_missing_type_rejected(self) -> None: + (self.bundle / "widget.md").write_text( + CONCEPT.replace("type: Subsystem Design\n", "") + ) + result = run(self.bundle) + self.assertEqual(result.returncode, 1) + self.assertIn("non-empty 'type'", result.stderr) + + def test_missing_frontmatter_rejected(self) -> None: + (self.bundle / "widget.md").write_text("# Widget\n") + result = run(self.bundle) + self.assertEqual(result.returncode, 1) + self.assertIn("missing YAML frontmatter", result.stderr) + + def test_summary_instead_of_description_rejected(self) -> None: + (self.bundle / "widget.md").write_text( + CONCEPT.replace("description:", "summary:") + ) + result = run(self.bundle) + self.assertEqual(result.returncode, 1) + self.assertIn("use 'description'", result.stderr) + + def test_index_frontmatter_rejected(self) -> None: + (self.bundle / "index.md").write_text( + ROOT_INDEX.replace('okf_version: "0.2"', "title: Bundle\nsummary: Nope.") + ) + result = run(self.bundle) + self.assertEqual(result.returncode, 1) + self.assertIn("may not carry frontmatter keys", result.stderr) + + def test_log_heading_format_enforced(self) -> None: + (self.bundle / "log.md").write_text("# Log\n\n## May 2026\n* Something.\n") + result = run(self.bundle) + self.assertEqual(result.returncode, 1) + self.assertIn("is not '## YYYY-MM-DD'", result.stderr) + + def test_unlisted_concept_rejected(self) -> None: + (self.bundle / "orphan.md").write_text(CONCEPT) + result = run(self.bundle) + self.assertEqual(result.returncode, 1) + self.assertIn("orphan.md: not listed in index.md", result.stderr) + + +if __name__ == "__main__": + unittest.main()