# 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, secrets-database, or discovery behavior. The integrating server translates these library calls into its own API and supplies its crates.io registry token when it initializes the library.
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, secrets, and backups
Construction receives a **Rust libraries root** and a crates.io registry token. The root's direct children are one directory per Rust library. It is the complete persistent library data set, so copying it wholesale intentionally backs up every managed Rust library without copying publishing authority.
`KcodeRustLibs::new(root, crates_io_registry_token)` converts the token to owned text, discards surrounding whitespace, rejects an empty result before creating either filesystem root, and retains the token in a private in-memory value. Cloned `KcodeRustLibs` values and opened library handles share that value. Its `Debug` representation is redacted. The library never discovers, reads, creates, or modifies a credential file on disk.
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 this library, Podman, and a separately supplied crates.io token; build state is disposable.
## 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.
- `src/lib.rs`, initially empty.
`Version.txt` is not created. The version returned by `docs()` comes from `Cargo.toml`.
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, loading, and legacy migration
`open_rust_lib(name)` recursively loads every file and initially validates the required metadata. If the valid library contains an ordinary root file named `Version.txt`, that obsolete file is removed and the library is loaded again before the opened handle is returned. A symlink or other unsupported entry is rejected rather than followed or removed. This one-time migration allows installations created by earlier releases to move to manifest-owned versions without adding a general deletion API.
Returned files are sorted lexicographically by `RustLibPath`; the removed legacy file is not returned. No other files are ignored. There is no separate load or reload call because opening is defined to load the complete Rust library.
Each opened handle receives a shared private reference to the registry token supplied at `KcodeRustLibs` initialization so publication does not perform credential discovery or disk access.
## 8. Required metadata and `docs()`
Every Rust library must contain root files named exactly `Cargo.toml` and `Documentation.md`.
The root manifest must contain a literal string `version` in its `[package]` table. Workspace-inherited versions are rejected. The value must be a canonical stable semantic version in `major.minor.patch` form. Numeric components follow SemVer rules, including no leading zeroes. A leading `v`, surrounding whitespace inside the string, prerelease suffix, build suffix, or partial version is invalid.
`Version.txt` is neither required nor authoritative.
`docs()` returns a `RustLibDocs` containing only:
- `version`: the canonical version parsed from the root `Cargo.toml`.
- `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 general 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 root manifest version. This 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. The version already held in `RustLibDocs` was parsed from that same root manifest, so no second version file is consulted. It uses the registry token supplied when the parent `KcodeRustLibs` value was initialized and performs no credential-file lookup.
Publication runs the complete token-free check, then creates another fresh source copy, Cargo home, and target directory and runs `cargo publish` with `--registry=crates-io` and `--no-verify`. The publication container starts Cargo from `/tmp` and addresses the library through `--manifest-path`, preventing an agent-authored `.cargo/config.toml` from controlling the registry or credential provider. The token is passed by environment-variable name, never embedded in command arguments, and exact-token-redacted from errors.
`--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.
## 12. Self-hosting
This repository is itself a conforming managed Rust library. Its root contains `Cargo.toml`, `Documentation.md`, and `src/lib.rs`; maintained files are ordinary UTF-8 files; and its version comes only from the root manifest. When its directory is named `kcode-rust-libs` beneath a Rust libraries root, an integrating server can initialize `KcodeRustLibs` with that root and its separately retrieved crates.io token, then an agent can open the library 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 generated state in disposable work directories outside the persistent root.
## 13. Integrating-server responsibilities
The integrating server provides protocol schemas, authentication, discovery, session ownership, concurrency exclusion, and secrets access. It must retrieve the crates.io token from its secrets database and pass it to `KcodeRustLibs::new`; this library does not know where or how secrets are persisted. If the server uses an asynchronous runtime, it should execute synchronous filesystem and Podman calls on blocking workers.
The server's agent-facing protocol should continue to expose create, open, write, check, and argument-free publish operations without exposing the initialization token. Operators provision and protect the secrets database; agents do not need disk or shell access and do not receive credentials.
## 14. Non-goals
The library does not provide a server, secrets database, on-disk credential discovery, Serde models, repository discovery, a general deletion API, Git, binary files, arbitrary commands, agent/session tracking, concurrency controls, persistent build caches, or generated-file synchronization.