# Kcode Rust Libs Specification
## 1. Purpose
`kcode-rust-libs` is a Rust library imported by a larger agent-tool server. It manages small, text-only Rust crates called **managed Rust libraries**, exposes their complete contents to an agent, validates them, and publishes them to crates.io.
This crate is not a server and defines no HTTP, RPC, MCP, authentication, session, connection-lifecycle, or discovery behavior. The integrating server translates these library calls into its own API.
The public vocabulary is `KcodeRustLibs`, `OpenedRustLib`, `RustLibFile`, and `RustLibPath`. The crate and library names are `kcode-rust-libs` and `kcode_rust_libs`.
## 2. Ownership and concurrency
The integrating server must ensure that at most one agent uses a Rust library at a time. It has the session information needed to release ownership after disconnects; this library does not. Consequently, the library has no locks, revisions, leases, close method, or stale-session recovery. Dropping `OpenedRustLib` has no filesystem side effects.
External modification of a Rust library while its handle is in use is unsupported.
## 3. Persistent storage and backups
Construction receives one **Rust libraries root**. Its direct children are:
- One directory per Rust library.
- Optionally, `cargo_registry_token.txt`.
This root is the complete persistent data set. Copying it wholesale intentionally backs up every Rust library and the crates.io credential. A backup therefore has publishing authority and must be protected like the original. The token is included deliberately; build output is not.
All validation and publication workspaces, Cargo homes, downloaded dependencies, package output, and target directories live in a process-specific directory under the operating system's temporary directory. The work root cannot overlap the Rust libraries root. Each operation uses a fresh copied source tree and removes it afterward when possible. The stored Rust library is never mounted into a container and generated files are never copied back.
Podman owns its image/container storage outside the Rust libraries root. The library embeds the tool image definition, versions the private image name from the crate version and definition, and builds it automatically if absent. A restored Rust libraries root on a fresh machine therefore needs only this library and Podman; build state is disposable.
The library never creates or modifies `cargo_registry_token.txt`. Its absence affects only publication.
## 4. Rust library names
A Rust library name is a string that is non-empty, begins with an ASCII letter or digit, and otherwise contains only ASCII letters, digits, hyphens, and underscores. It is used as one directory component and as the initial Cargo package name. Names are case-sensitive where the filesystem is case-sensitive.
No listing or discoverability API is provided because the integrating system already knows which Rust libraries exist.
## 5. Creation
`create_rust_lib(name)` fails if the destination exists and otherwise creates and opens a Rust 2024 library containing:
- `Cargo.toml` with package name `name` and version `0.1.0`.
- `Documentation.md`, initially empty.
- `Version.txt`, containing `0.1.0` and one trailing newline.
- `src/lib.rs`, initially empty.
The metadata files exist from creation so every successfully opened handle can provide `docs()` without a second filesystem operation. Failed creation removes the partial directory when possible.
## 6. Rust library paths and contents
`RustLibPath` is a canonical UTF-8 path relative to the Rust library root, represented with `/`. It must be non-empty, cannot begin or end with `/`, and cannot contain empty, `.`, or `..` components, backslashes, colons, or NUL. Input is rejected rather than normalized. Dotfiles and Unicode components are permitted.
The path type prevents lexical traversal. Filesystem operations additionally reject symlinks because symlinks are filesystem objects, not path syntax.
Every filename and file body must be UTF-8. Rust libraries may contain ordinary files and directories only. Opening fails on a symlink, special file, non-UTF-8 name, or non-UTF-8 body. No path, content-size, depth, file-count, or aggregate-size limits are imposed; small enough to remain in agent context is a usage constraint rather than a library policy.
## 7. Opening and loading
`open_rust_lib(name)` recursively loads every file and returns them sorted lexicographically by `RustLibPath`. No files are ignored. Opening also validates the required metadata described below. There is no separate load or reload call because opening is defined to load the complete Rust library.
## 8. Required metadata and `docs()`
Every Rust library must contain root files named exactly `Documentation.md` and `Version.txt`.
`Version.txt` must contain a canonical stable semantic version in `major.minor.patch` form, optionally followed by exactly one LF newline. Numeric components follow SemVer rules, including no leading zeroes. A leading `v`, surrounding whitespace, prerelease suffix, build suffix, additional line, or partial version is invalid.
`docs()` returns a `RustLibDocs` containing only:
- `version`: the canonical version without a trailing newline.
- `documentation`: the complete text of `Documentation.md`, not a file object.
This small response exists for consumers that need agent-facing usage information without loading or extracting the complete file list.
## 9. Writing
`write(files)` accepts a batch of complete `RustLibPath`/text pairs. It creates missing parent directories and creates or truncates each supplied file. Omitted files remain unchanged. It does not provide patches, deletions, renames, or directory operations.
Before writing anything, it rejects duplicate paths, invalid targets, symlink traversal, a projected state missing either required metadata file, or an invalid projected `Version.txt`. This explicitly preserves the `docs()` invariant when metadata is overwritten. Other writes are sequential rather than transactional: an operating-system failure can occur after an earlier file was replaced. Following success, the complete in-memory file list and documentation metadata are refreshed.
## 10. Check pipeline
`check()` runs the entire standardized suite on a disposable copy. Stages execute in order and stop at the first failure:
1. `cargo fetch --color never`
2. `cargo fmt --all -- --check`
3. `cargo build --workspace --all-targets --all-features --locked --offline --color never`
4. `cargo clippy --workspace --all-targets --all-features --locked --offline --color never -- -D warnings`
5. `cargo test --workspace --all-targets --all-features --locked --offline --no-fail-fast --color never`
6. `cargo test --workspace --all-features --doc --locked --offline --no-fail-fast --color never`
Fetch has normal container networking so it can resolve dependencies and generate or update a lockfile inside the copy. Later stages have no network and use Cargo offline mode. Each stage uses a new foreground Podman container with automatic removal, a read-only root, all capabilities dropped, `no-new-privileges`, the caller's rootless user mapping, no TTY, a writable `/tmp`, and writable mounts limited to that run's source copy, Cargo home, and target directory.
The library imposes no timeout, CPU, memory, or output limit. The integrating server may supervise the synchronous call.
A source-quality or test failure is `Ok(CheckResult)` with `passed() == false`; completed stages retain exit code, stdout, and stderr without truncation. Workspace or Podman failures are `Err(Error)`.
## 11. Publication
`publish()` publishes the root `Cargo.toml` package to crates.io and accepts no arguments. Agents never provide, retrieve, or receive registry credentials.
Publication proceeds as follows:
1. Read the literal version string from the root `Cargo.toml` `[package]` table. It must equal `Version.txt`; inherited workspace versions are rejected to keep the published package unambiguous.
2. Run the complete `check()` pipeline without placing the registry token in any container environment. A failed check aborts publication and is returned as `Error::CheckFailed(CheckResult)`.
3. Read `<rust-libraries-root>/cargo_registry_token.txt` as UTF-8, trim surrounding whitespace, and reject a missing or empty token.
4. Create another fresh source copy, Cargo home, and target directory.
5. Run `cargo publish` in a fresh Podman container with normal networking, `--registry=crates-io`, `--no-verify`, and Cargo's built-in `cargo:token` credential provider.
The publication container starts Cargo from `/tmp` and addresses the Rust library through `--manifest-path`. This prevents an agent-authored `.cargo/config.toml` in the Rust library from controlling the publication registry or credential provider. The token is placed in the Podman process environment and passed into the container by variable name, never embedded in command arguments. It is not written to the disposable Cargo home, stored in the Rust library, returned, or logged by the library.
`--no-verify` is intentional: the full build and test suite has already passed in a token-free container, and disabling Cargo's second verification build ensures agent-authored build scripts or tests cannot execute while the token is present. Cargo still packages and uploads the crate, and crates.io remains responsible for ownership, package-name, metadata, and duplicate-version rules.
Any Cargo rejection is an error containing Cargo's captured diagnostic output. The token itself is never included in that error by this library.
## 12. Self-hosting
This repository is itself a conforming managed Rust library. Its root contains `Cargo.toml`, `Documentation.md`, `Version.txt`, and `src/lib.rs`; the literal Cargo package version equals `Version.txt`; and maintained files are ordinary UTF-8 files. When its directory is named `kcode-rust-libs` beneath a Rust libraries root, an agent can open it with `open_rust_lib("kcode-rust-libs")` and maintain its complete source, tests, specification, and documentation through `files()`, `docs()`, and `write()`.
Generated build output, editor swap files, and other binary artifacts must remain outside a managed Rust library because opening intentionally loads every file as UTF-8. The standard `check()` and `publish()` implementations satisfy this constraint by keeping all generated state in disposable work directories outside the persistent root.
## 13. Integrating-server responsibilities
The integrating server provides protocol schemas, authentication, discovery, session ownership, and concurrency exclusion. If it uses an asynchronous runtime, it should execute synchronous filesystem and Podman calls on blocking workers. Operators provision and protect `cargo_registry_token.txt`; agents do not need disk or shell access and must not be given a token parameter.
## 14. Non-goals
The library does not provide a server, Serde models, repository discovery, deletion, Git, binary files, arbitrary commands, agent/session tracking, concurrency controls, persistent build caches, or generated-file synchronization.