# Contributing to oxo-call
Thank you for your interest in improving **oxo-call**! This guide covers
everything you need to get started: setting up a development environment,
understanding the codebase, adding skills and workflows, and submitting
high-quality pull requests.
---
## Table of contents
- [Development setup](#development-setup)
- [Project structure](#project-structure)
- [Adding a new skill](#adding-a-new-skill)
- [Adding workflow templates](#adding-workflow-templates)
- [Code style](#code-style)
- [Testing](#testing)
- [Documentation](#documentation)
- [Pull request guidelines](#pull-request-guidelines)
- [Issue guidelines](#issue-guidelines)
- [License](#license)
---
## Development setup
### Prerequisites
| [Rust](https://rustup.rs/) | 1.85+ (edition 2024) | Build and test |
| Git | 2.x | Version control |
| [mdBook](https://rust-lang.github.io/mdBook/) | 0.4+ | Documentation (optional) |
### Clone and build
```bash
git clone https://github.com/Traitome/oxo-call.git
cd oxo-call
# Debug build
cargo build --verbose
# Release build (LTO + strip enabled)
cargo build --release
```
### Run the test suite
```bash
# All tests
cargo test --verbose
# A single integration test file
cargo test --test cli_tests
# A single test by name
cargo test --test cli_tests test_help_output -- --exact
```
### Lint and format
```bash
# Check formatting
cargo fmt -- --check
# Apply formatting
cargo fmt
# Run clippy with warnings denied (CI enforces this)
cargo clippy -- -D warnings
```
### Install locally
```bash
cargo install --path .
```
---
## Project structure
```
oxo-call/
├── Cargo.toml # Workspace root
├── src/
│ ├── main.rs # Entry point; license gate + command dispatch
│ ├── cli.rs # Clap command tree (run, dry-run, docs, config, …)
│ ├── runner.rs # Core orchestration: docs → skill → LLM → execute
│ ├── docs.rs # Documentation resolver (cache, help, remote)
│ ├── index.rs # Persistent documentation index
│ ├── skill.rs # Skill system: built-in, community, user skills
│ ├── llm.rs # Prompt building and ARGS:/EXPLANATION: parsing
│ ├── config.rs # Platform-aware configuration
│ ├── history.rs # JSONL command history
│ └── license.rs # Offline Ed25519 license verification
├── skills/ # 143 built-in skill TOML files
├── workflows/
│ ├── native/ # .oxo.toml workflow format
│ ├── snakemake/ # Snakemake (.smk) templates
│ └── nextflow/ # Nextflow (.nf) templates
├── crates/
│ ├── license-issuer/ # Maintainer-only license signing tool
│ └── oxo-bench/ # Benchmarking crate
├── tests/
│ ├── cli_tests.rs # Integration tests (binary execution)
│ └── fixtures/ # Test license and data
├── docs/
│ └── guide/ # mdBook documentation source
└── .github/
└── workflows/ci.yml # CI: fmt, clippy, test, multi-platform build
```
### Execution flow
1. `main.rs` — Parses CLI args, enforces the license gate (all commands
except `license`, `--help`, `--version` require a valid license).
2. `runner.rs` — For `run`/`dry-run`: fetches tool documentation **first**,
loads any matching skill, builds the LLM prompt, optionally executes the
tool, and records history.
3. `llm.rs` — Sends the prompt and expects a strict response containing
`ARGS:` and `EXPLANATION:` lines (retries on format errors).
---
## Adding a new skill
Skills ground the LLM in domain-specific knowledge. Each skill is a TOML
file that lives in `skills/`.
### 1. Create the TOML file
Create `skills/<toolname>.toml` following this structure:
```toml
[meta]
name = "toolname"
category = "alignment" # e.g. alignment, variant-calling, qc, …
description = "One-line summary of the tool"
tags = ["bam", "alignment"] # Relevant search keywords
author = "oxo-call built-in"
source_url = "https://tool-docs.example.com"
[context]
concepts = [
"Key concept the LLM should know when generating arguments.",
"Another concept — be specific and actionable.",
]
pitfalls = [
"Common mistake users make with this tool.",
"Another pitfall — explain what goes wrong and the fix.",
]
[[examples]]
task = "Sort a BAM file by coordinate"
args = "sort -@ 4 -o sorted.bam input.bam"
explanation = "-@ 4 uses 4 threads; -o writes output; coordinate sort is the default"
[[examples]]
task = "Another representative task"
args = "view -b -q 30 input.bam"
explanation = "Filters to reads with MAPQ ≥ 30 and outputs BAM"
```
**Tips:**
- `args` should contain only the arguments, **not** the tool name itself.
- Include 3–6 representative examples covering common use cases.
- Concepts and pitfalls directly shape the LLM prompt—make them concise and
accurate.
### 2. Register the skill in `src/skill.rs`
Add an entry to the `BUILTIN_SKILLS` array using the `builtin!` macro:
```rust
const BUILTIN_SKILLS: &[(&str, &str)] = &[
// … existing entries …
builtin!("toolname"), // ← add this line
];
```
Place the entry in the appropriate category section (the array is grouped by
bioinformatics domain).
### 3. Verify
```bash
cargo build --verbose
cargo test --verbose
```
Ensure the new skill appears in `oxo-call skill list` and that
`oxo-call skill show <toolname>` renders correctly.
---
## Adding workflow templates
Workflow templates live under `workflows/` in three formats:
| `workflows/native/` | oxo-call native | `.oxo.toml` |
| `workflows/snakemake/` | Snakemake | `.smk` |
| `workflows/nextflow/` | Nextflow | `.nf` |
To add a new template:
1. Create the workflow file in the appropriate subdirectory.
2. Include a header comment describing the analysis, required inputs, and
expected outputs.
3. Reference only tools that have corresponding skill files in `skills/`.
4. Test locally with `oxo-call workflow show <name>` if applicable.
---
## Code style
- **Formatting**: `cargo fmt` — the CI enforces `cargo fmt -- --check`.
- **Linting**: `cargo clippy -- -D warnings` — all warnings are errors in CI.
- **Comments**: Only add comments where the logic is non-obvious. Avoid
restating what the code already says.
- **Error handling**: Use `anyhow::Result` for application errors and
`thiserror` for library-level typed errors.
- **Naming**: Follow standard Rust conventions (`snake_case` for functions
and variables, `PascalCase` for types).
---
## Testing
### Integration tests
Tests in `tests/cli_tests.rs` execute the compiled binary with
`std::process::Command`. A fixture license is injected via the
`OXO_CALL_LICENSE` environment variable.
```rust
fn oxo_call() -> Command {
let mut cmd = Command::cargo_bin("oxo-call").unwrap();
cmd.env("OXO_CALL_LICENSE", test_license_path());
cmd
}
```
When writing new integration tests:
- Use `oxo_call()` for commands that require a license.
- Use `oxo_call_no_license()` for testing license enforcement.
- Assert on both stdout content and exit codes.
- Run `cargo test --test cli_tests` to validate.
### Unit tests
Add `#[cfg(test)]` modules inside the relevant source file. Keep unit tests
focused on a single function or struct.
### Running all tests
```bash
cargo test --verbose
```
CI runs the full test matrix on every PR across Linux, macOS, and Windows.
---
## Documentation
The user-facing guide is built with [mdBook](https://rust-lang.github.io/mdBook/)
from source files in `docs/guide/src/`.
### Build docs locally
```bash
cd docs/guide
mdbook serve # Live-reload at http://localhost:3000
mdbook build # Static output in docs/guide/book/
```
### When to update docs
- Adding a new subcommand → update the relevant guide page.
- Changing config options → update the configuration reference.
- Adding a skill or workflow → mention it in the tools/skills section.
CI automatically deploys the guide to GitHub Pages on pushes to `main`.
---
## Pull request guidelines
1. **Branch from `main`** — use descriptive branch names like
`feat/add-blast-skill` or `fix/config-path-windows`.
2. **Keep PRs focused** — one feature or fix per PR. Large PRs are harder to
review.
3. **Pass CI** — ensure all of the following pass before requesting review:
```bash
cargo fmt -- --check
cargo clippy -- -D warnings
cargo test --verbose
```
4. **Write a clear description** — explain *what* changed and *why*. Link
related issues with `Closes #123`.
5. **Add tests** — new features need integration tests; bug fixes need
regression tests.
6. **Update documentation** — if user-facing behavior changes, update the
relevant mdBook pages and/or `--help` text.
7. **License gate awareness** — if you change command flow in `main.rs`,
preserve the rule that core commands require a valid license while
`license`, `--help`, and `--version` work without one.
8. **Keep `license.rs` and `license-issuer` in sync** — the issuer signs
the same payload shape that the runtime verifies; schema changes must be
coordinated across both crates.
---
## Issue guidelines
When opening an issue:
- **Bug reports** — include the oxo-call version (`oxo-call --version`),
OS, the exact command you ran, and the full error output.
- **Feature requests** — describe the use case, not just the desired
solution.
- **Skill requests** — mention the tool name, homepage, and a few example
tasks you'd like supported.
---
## License
oxo-call uses a **dual-license model**:
| Academic, educational, personal research | [Academic License](LICENSE-ACADEMIC) | Free |
| Commercial / for-profit | [Commercial License](LICENSE-COMMERCIAL) | Paid |
By contributing to this repository, you agree that your contributions will
be licensed under the same terms. See [LICENSE](LICENSE) for the full
details.
If you have licensing questions, contact **license@traitome.com**.