Workspace and crates
Note
Project policy: draft. This page is the only home of Shiin’s crate list. The workspace has twelve product crates and
xtask, including partial approval, evidence, and integration implementations. Host, platform, and milestone validation remain incomplete.
Shiin is built as a single Cargo workspace. This page describes the repository layout, the crates in the workspace, what each crate is responsible for, and the rules that keep the crate graph small, acyclic, and honest about what exists. The decision behind the layout is ADR-0035.
What exists today
| Path | State | Purpose |
|---|---|---|
Cargo.toml | exists | Virtual workspace manifest with shared package metadata, [workspace.dependencies], and [workspace.lints] |
rust-toolchain.toml | exists | Pinned toolchain; see Toolchain and MSRV |
rustfmt.toml, .editorconfig | exist | Formatting rules; see Coding standards |
.cargo/config.toml | exists | Defines the cargo xtask alias |
xtask/ | exists | Repository tooling; today it provides cargo xtask docs-check |
crates/ | exists | Product crates, each created in the milestone that needs it |
fuzz/ | exists | Wire-request and classification fuzz targets in a separate nightly workspace |
The workspace section of today’s Cargo.toml is:
[workspace]
resolver = "3"
members = [
"crates/shiin-approval",
"crates/shiin-audit",
"crates/shiin-classify",
"crates/shiin-client",
"crates/shiin-cli",
"crates/shiin-engine",
"crates/shiin-hooks",
"crates/shiin-ipc",
"crates/shiin-mcp-proxy",
"crates/shiin-policy",
"crates/shiin-schema",
"crates/shiind",
"xtask",
]
The alias in .cargo/config.toml is:
[alias]
xtask = "run --quiet --package xtask --"
Layout
Cargo.toml virtual workspace manifest (no root package)
rust-toolchain.toml pinned toolchain
rustfmt.toml formatter settings
.editorconfig editor settings
.cargo/config.toml cargo aliases, including `cargo xtask`
crates/<name>/ twelve product crates with milestone validation in progress
xtask/ repository tooling, never published
fuzz/ fuzz targets, a separate nightly workspace
docs/ this documentation
- The root
Cargo.tomlis a virtual manifest. It has no[package]section, so no crate is privileged by living at the root. - Product crates live in
crates/<name>/, and the directory name is the crate name. xtask/follows thecargo xtaskconvention for repository automation written in Rust. It setspublish = false. Product crates never depend on it.- The
fuzz/directory has its own[workspace]table and lockfile. Its nightly-only dependencies never enter the main workspace, its lockfile, or its MSRV check. See Testing strategy. - Every member inherits
edition,rust-version,license,repository, andauthorsfrom[workspace.package]. - Every member sets
[lints] workspace = true, exceptshiin-platform, which declares its own table as described in Coding standards.
Crates
The table lists every product crate in the workspace, its responsibility, and the milestone that owns its implementation and validation.
| Crate | Responsibility | Milestone |
|---|---|---|
shiin-schema | Wire types for action requests, decisions, approval messages, and audit events, matching the JSON Schemas in docs/spec/schemas/ | v0.1 |
shiin-classify | Normalizers for paths, shell commands, URLs, and experimental SQL, and the derivation of effects from them | v0.1 (SQL: v0.5; host integration open) |
shiin-policy | The TOML front-end and its compilation to Cedar, policy layering, and diagnostics | v0.1 |
shiin-engine | The pure, synchronous evaluation pipeline | v0.1 |
shiin-audit | The hash-chained audit log, verification, replay, and receipts behind a feature | v0.1 (receipts: v0.4; external review open) |
shiin-hooks | Host hook adapters: a claude_code module, then codex and cursor modules | v0.1 (Codex and Cursor: v0.2) |
shiin-cli | The shiin binary: init, check, explain, policy validate, policy test, hook, task, pending, approve, log, verify, replay, and doctor | v0.1 |
shiin-approval | The approval state machine and grants | v0.3 (source; review open) |
shiin-ipc | Local transport over Unix domain sockets and Windows named pipes | v0.3 (Unix source; Windows validation open) |
shiind | The per-user daemon | v0.3 (Unix source; platform validation open) |
shiin-client | The Rust client for daemon evaluation and policy validation | v0.5 (early source; conformance open) |
shiin-mcp-proxy | The MCP proxy with upstream stdio and downstream stdio or Streamable HTTP | v0.5 (HTTP: v0.6; external conformance open) |
shiin-platform | The only crate allowed to contain unsafe code; created only if needed | as needed |
xtask | Repository tooling | exists |
fuzz/ | Fuzz targets; a separate workspace, not a member crate | v0.1 |
shiin-cli gains its subcommands milestone by milestone; the CLI reference says which command arrives when.
The engine crates are shiin-schema, shiin-classify, shiin-policy, and shiin-engine.
Several rules on this page and on Async and concurrency apply to that group.
Rules
Never pre-create crates
- A crate is created in the pull request that adds its first real functionality, in the milestone the table names.
- Empty, placeholder, or “coming soon” crates are not created, in the repository or on crates.io. Crate names are not reserved on crates.io in advance.
- A pull request that adds, splits, merges, or renames a crate updates the table on this page in the same change.
- A change that alters the dependency direction below, or adds a crate to the set of stable public APIs, needs an ADR.
Stable and internal APIs
shiin-schemaandshiin-clientare the only crates intended to become stable public APIs. Other projects may depend on them, and after 1.0 they follow the guarantees in Versioning and stability.- Every other product crate is published to crates.io, because a published crate can only depend on other published crates, but is documented as internal before 1.0. Its crate-level documentation starts with a sentence saying that the API is internal to Shiin and can change in any release.
xtaskis never published.
Dependencies are declared once, with default features off
- Every third-party dependency is declared in
[workspace.dependencies]with a version requirement anddefault-features = false. - Members reference it with
workspace = trueand enable only the features they use. - Default features have to be disabled at the workspace level: a member can add features to a workspace dependency but cannot remove default features that the workspace entry leaves enabled.
- Admitting a dependency at all is governed by Dependencies and supply chain.
Today’s Cargo.toml does not fully follow this rule yet.
jsonschema sets default-features = false, but the regex, serde_json, and walkdir entries do not.
Several product dependencies also retain default features.
Reviewing and disabling unnecessary defaults remains open supply-chain work.
No networking in the engine crates
- The engine crates never open network connections and never depend on crates that do, such as HTTP clients, TLS stacks, or async runtimes.
shiin-engineperforms no I/O of any kind (ADR-0010).shiin-classifyandshiin-policymay read the local file system where their job requires it, such as resolving a path or loading a policy file.cargo xtask dependency-checkinspects the normal (non-dev) dependency tree of each engine crate and fails if a known network stack or async runtime appears. The documentation CI job runs this check; the prohibited-crate list still needs review when new dependencies are admitted.
shiin-engine builds for WebAssembly as a purity guard
From v0.4, CI builds shiin-engine for the wasm32-unknown-unknown target on every pull request.
The isolated check disables the schema crate’s default runtime feature through its workspace dependency.
OS clocks and randomness remain explicitly enabled by adapters and services; wire types and timestamp formatting do not require them.
- The build fails if the engine, or anything it depends on, needs operating-system facilities that target lacks, such as native system libraries, platform-specific system calls, or an operating-system randomness source. That makes it a cheap, continuous guard against I/O and platform dependencies creeping into the engine.
- The guard is not complete.
The standard library still compiles calls such as file and socket operations for that target and only fails at run time,
so the build does not catch them.
Planned
disallowed_methodsanddisallowed_typesClippy configuration for the engine crates covers that gap. - The guard starts at v0.4, when replay makes the engine’s determinism a guarantee users rely on.
- Building for this target is a test, not a support promise. Supported platforms are listed in Platform support.
Dependency direction
Dependencies point from binaries, through adapters and services, down to the engine crates, and never back up.
shiin-platform, if it is ever created, sits below everything that needs it and depends on no other Shiin crate.
flowchart TD
subgraph binaries["Binaries"]
cli["shiin-cli<br/>(shiin)"]
daemon["shiind"]
proxy["shiin-mcp-proxy"]
end
subgraph services["Adapters, approvals, evidence, and transport"]
hooks["shiin-hooks"]
approval["shiin-approval"]
audit["shiin-audit"]
client["shiin-client"]
ipc["shiin-ipc"]
end
subgraph enginecrates["Engine crates: no networking"]
engine["shiin-engine"]
policy["shiin-policy"]
classify["shiin-classify"]
schema["shiin-schema"]
end
platform["shiin-platform<br/>(only if needed)"]
binaries --> services
binaries --> enginecrates
services --> enginecrates
client --> ipc
engine --> policy
engine --> schema
policy --> schema
classify --> schema
binaries -.-> platform
services -.-> platform
classify -.-> platform
The diagram is enforced by these rules:
- A crate never depends on a crate in a group above it, and libraries never depend on binaries.
- The engine crates depend only on each other and on third-party crates that satisfy the no-networking rule.
shiin-enginedoes not depend onshiin-classify. Adapters classify what a host reports into an action request; the engine only evaluates action requests.shiin-clientdepends only onshiin-schema,shiin-ipc, and third-party crates, so embedding the public client library never pulls in Cedar or the engine.shiin-platformdepends on no other Shiin crate.shiin-engineandshiin-schemanever depend on it.xtaskmay depend on product crates, for example to validate examples against real types; no product crate depends onxtask.
Dependencies within a group are allowed when they respect these rules; Cargo rejects cycles.
Adding a crate
- Confirm the crate is in the table for the current milestone, or update the table in the same pull request.
- Create
crates/<name>/Cargo.tomlinheriting the[workspace.package]fields and[lints] workspace = true. - Write crate-level documentation stating the crate’s responsibility and, before 1.0, that its API is internal (unless it is
shiin-schemaorshiin-client). - Admit each new dependency under Dependencies and supply chain.
- If the crate is security-sensitive, add it to Security-sensitive changes.
Related pages
- Architecture overview maps components to these crates.
- Toolchain and MSRV
- Coding standards
- Unsafe code policy