Skip to main content

Contributing

Pull requests are welcome, and there is no invitation to wait for. This is a small project; the useful thing is usually not a large feature but a row in a table, a sentence in a translation, or a bug report detailed enough to act on.

The most useful contributions​

A row in the model table. Checking a model is a fixed five-minute task. The table is short because it only holds models somebody ran, and a negative result is worth as much as a positive one — nobody posts about the model that did not work, so everybody rediscovers it.

A translation, or one line of a correction to one. Ten ship. Any of them can be corrected one sentence at a time without touching the rest — see Languages. A new language is a single JSON file.

A bug report with the four things. The model and provider written exactly (qwen3-coder:30b on Ollama, not "a local model"), what you asked, what happened, and fifty lines of ~/.opencli/log from around the failure. Check those log lines for keys before you paste them.

Telling us what you actually wanted to do. The built-in departments and skills were written from guesses about what people need. The thing you reached for and did not find is the most useful thing you can say.

Before you write code​

Open an issue first for anything larger than a fix. Not as a gate — so the approach can be agreed before you spend an evening on it. A PR that arrives with no issue behind it still gets read.

Setting up​

Rust and pnpm; the workspace is opencli-rs/, the web interface is web/, and the desktop shell is desktop/.

git clone https://github.com/ai-dashboad/opencli
cd opencli
pnpm install
cargo build -p opencli-cli

just from the repo root runs the workspace helpers; just help lists them.

Before you open the PR​

just fmt
just fix -p <crate> # clippy, on the crate you touched
cargo test -p <crate>

Do not run a bare cargo fmt. The tree is formatted with imports_granularity=Item, which is nightly-only. On stable that option is silently ignored, so cargo fmt rewrites the import block of nearly every file in the workspace and buries your change in hundreds of unrelated diffs. just fmt invokes nightly for exactly this reason. Without a nightly toolchain (rustup toolchain install nightly), format only the files you touched and let CI confirm the rest.

If you touched the web interface, python3 scripts/i18n-check.py finds English that was never wrapped for translation — including the cases that are easy to miss, like text split by an inline tag and labels built at import time.

What makes a PR easy to merge​

  • One thing. Unrelated fixes are separate PRs.
  • A test that fails before your change and passes after. Not full coverage — one assertion that would have caught the bug.
  • Commits that each build. It makes review and rollback possible.
  • Documentation, if behaviour changed. The README, opencli --help, or the page here that is now wrong.
  • What, why, how in the description. The why is the part that cannot be read off the diff.

No CLA​

There is nothing to sign. Contributions are under Apache-2.0, like the rest of the tree.

Reporting a vulnerability​

Do not open a public issue for a security bug. Use GitHub's private advisory form, which reaches the maintainers without publishing anything.

The parts most worth looking at: the sandbox policy, the approval path, and anything that decides what a tool call is allowed to touch. An agent that reads your files and runs commands on your machine has a large surface, and it is better for you to find it than for somebody else to.

Being decent about it​

Treat people with respect; we follow the Contributor Covenant. Assume good intent — written communication is hard, so err on the side of generosity. If something is confusing, that is worth an issue on its own: confusing documentation is a bug in the documentation.