apexe is an Outside-In CLI-to-Agent Bridge — automatically wraps existing CLI tools into governed apcore modules, served via MCP/A2A.
- Use precise, full-word names; standard abbreviations only when idiomatic (
buf,cfg,ctx). - Functions ≤50 lines, single responsibility, verb-named (
parse_request,build_schema). - Avoid obscure tricks, overly chained iterators, unnecessary macros, or excessive generics.
- Break complex logic into small, well-named helper functions.
- Provide explicit types on all public items; do not rely on inference for public API surfaces.
- Prefer
structover raw tuples for anything with more than 2 fields. - Use
newtypewrappers (struct TaskId(Uuid);) to encode domain semantics. - Use
enumfor exhaustive variants; avoid stringly-typed logic. - Implement
serde::Serialize/serde::Deserializeon all public data types.
- Favor composition over inheritance; use
traitonly for true behavioral interfaces. - Prefer plain functions + data structs; minimize trait object (
dyn Trait) indirection. - No circular module dependencies.
- Use dependency injection (constructor arguments) for config, logging, DB connections, etc.
- Keep
pubsurface minimal — default to module-private, expose only what consumers need.
- Define domain errors with
thiserror; no bareBox<dyn Error>in library code. - Propagate errors with
?; nounwrap()/expect()in library paths (tests excepted). - If
unwrap()/expect()is truly unreachable, document with a// SAFETY:or// INVARIANT:comment. - Validate and sanitize all public inputs at crate boundaries.
- Use RAII /
Dropfor resource cleanup; avoid manual teardown.
- Runtime: Tokio (
features = ["full"]). - Never block the async executor — use
tokio::task::spawn_blockingfor CPU-heavy work. - Use
tokio::time::sleep/tokio::time::timeout, notstd::thread::sleep.
- Use
tracing— noprintln!/eprintln!in production code. - Level guide:
tracing::error!— unrecoverable failurestracing::warn!— recoverable anomaliestracing::info!— key business eventstracing::debug!— internal state for debugging
- Always include structured fields:
tracing::info!(task_id = %id, "task started").
- Run with:
cargo test --all-features - Unit tests: in the same file under
#[cfg(test)] mod tests { ... }. - Integration tests: in
tests/directory. - Test names:
test_<unit>_<behavior>(e.g.,test_parse_request_returns_error_on_empty_body). - Never change production code without adding or updating corresponding tests.
- Use
tokio-testfor async test helpers.
- JSON:
serde_json. YAML:serde_yaml. - Avoid manual
Serialize/Deserializeimpls unless schema shape requires it.
Run make check before every commit (mirrors CI exactly):
| Command | Purpose |
|---|---|
cargo fmt --all -- --check |
Formatting |
cargo clippy --all-targets --all-features -- -D warnings |
Lint (warnings = errors) |
apdev-rs check-chars src/ |
Character validation |
cargo build --all-features |
Full build |
cargo test --all-features |
Tests |
make setup # One-time: installs apdev-rs + pre-commit hook
make fmt # Auto-format
make check # Run all gates (do this before git commit)#[allow(...)]to silence Clippy requires an inline comment explaining why.#[rustfmt::skip]is forbidden without documented justification.Cargo.lockmust be committed (reproducible CI builds).
- All
uses:actions must be pinned to a full commit SHA (not just a tag):uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- Workflow default permissions:
contents: read(minimum privilege).
- Evaluate necessity before adding a new dependency.
- Specify minimum compatible versions; avoid over-pinning patch versions.
- Dev-only crates go in
[dev-dependencies], never[dependencies].
- English only for all code, comments, doc comments, error messages, and commit messages.
- Fully understand surrounding code before making changes.
- Do not generate unnecessary documentation stubs, example files, or boilerplate unless explicitly requested.
- No secrets hardcoded — use environment variables or configuration files.