Command Line Interface
Genja provides a first-party CLI crate, genja-cli, for listing, describing,
and documenting registered task descriptors. It discovers compiled Rust tasks
and configured Python task modules from the selected project file.
Choose Your Project Setup
Select the workflow that matches your project. The task commands, output formats, identity rules, and errors in the command reference apply to all three.
Starting with v0.5.0, install both genja-py and the prebuilt genja
command in the Python environment containing your task modules:
python -m pip install "genja-py[cli]>=0.5.0,<0.6.0"
Python discovery requires v0.5.0 or later of both packages. See Installation for supported wheel platforms.
Declare the modules containing your @task classes in pyproject.toml:
[tool.genja.tasks]
modules = ["my_project.tasks.network", "my_project.tasks.backups"]
Genja imports these modules during discovery, so task authors do not need an application import or a separate registry call. From the project directory, run:
genja task list
genja task describe acme.examples.backup_config@1.0.0
genja task docs
The identity above comes from the
Python example; use an
identity from your own task list output. genja --help lists commands,
and genja version prints the CLI version.
The CLI reads pyproject.toml in the current directory. A genja binary
installed from a Python wheel uses the interpreter beside it; a Cargo-built
binary uses python from PATH. Pass a path to --pyproject to select
another project file, or to --python to select another interpreter. See
Task Registration for the
import boundary.
Build a project-local CLI binary
that links your Rust task registrations. The generic installed genja
binary cannot see tasks linked only into your project binary.
my_project_cli task list
my_project_cli task describe acme.examples.backup_config@1.0.0
my_project_cli task docs
Without [tool.genja.tasks], discovery uses the linked Rust tasks and
does not start Python.
Build a project-local CLI binary
that links your Rust task crate. Install genja-py alongside your Python
task modules in the selected interpreter and declare those modules in the
project's pyproject.toml:
[tool.genja.tasks]
modules = ["my_project.tasks.network", "my_project.tasks.backups"]
The same binary combines linked Rust tasks with descriptors from the imported Python modules:
my_project_cli task list
my_project_cli task describe python:acme.examples.backup_config@1.0.0
my_project_cli task docs
The qualified identity is from the
mixed example; use an
identity from your own list. The CLI uses pyproject.toml in the current
directory and python from PATH by default. Pass a path to
--pyproject or --python to override either choice. Configured Python
failures stop discovery without printing partial Rust results.
Terminal User Interface (TUI)
Genja provides an interactive task browser for the terminal. A binary
built with the tui feature can browse configured Python tasks and linked Rust
tasks in one screen. Rust applications can also embed the browser. Press q
outside search to quit; Escape first returns from inspection or clears search.
Builds without the feature omit the command. See
the Terminal UI guide for setup, usage, and current capabilities.
Command Reference (All Projects)
The tabs below use genja for Python-only projects and my_project_cli for
Rust or mixed projects. Commands and flags are otherwise the same. See
Project-Local CLI Binary
for Rust and mixed setup instructions.
The example task identities are illustrative; use the ID and version returned
by your binary's task list command.
Help And Version
genja --help
genja version
genja task --help
genja task list --help
genja task describe --help
genja task docs --help
my_project_cli --help
my_project_cli version
my_project_cli task --help
my_project_cli task list --help
my_project_cli task describe --help
my_project_cli task docs --help
my_project_cli --help
my_project_cli version
my_project_cli task --help
my_project_cli task list --help
my_project_cli task describe --help
my_project_cli task docs --help
version prints the linked Genja CLI version, not your project's package version.
Terminal Task Browser
With the tui feature on genja-cli, or genja-tui on genja, the generic
genja binary or a project-local binary can launch the terminal browser:
genja tui --help
genja tui
my_project_cli tui --help
my_project_cli tui
my_project_cli tui --help
my_project_cli tui
Run it in an interactive terminal and press q or Escape to exit. The screen
shows one searchable task table with Rust and Python language icons. Enter opens
Details and Tab switches to Schema inspection. Task execution is not implemented.
Builds without TUI support omit this command. See the
Terminal UI guide for setup and terminal behaviour.
Try The Sample Tasks (Rust Checkout)
These commands require a local checkout of the Genja GitHub repository.
Run them from that checkout's root, where its workspace Cargo.toml lives.
Running cargo add genja in your own project does not make Genja's example
executables available through cargo run --example. See
Examples for checkout instructions.
In the checkout, run task_browser to explore two sample tasks without
creating your own project-local binary:
cargo run -p genja --features genja-cli --example task_browser -- task list
cargo run -p genja --features genja-cli --example task_browser -- task describe acme.examples.backup_config@1.0.0
cargo run -p genja --features genja-tui --example task_browser -- tui
The example links a blocking, constructible backup_config task and an async,
descriptor-only collect_facts task with a generated local ID. To describe the
second task, use its ID and version from task list in <id>@<version> form.
Add --output json to a list or describe command to inspect the descriptor data.
The sample implementations do not perform backups or connect to hosts.
Registrations belong only to the example executable. The TUI currently loads
both descriptors and displays them in a navigable, searchable table. Press /
to search and Enter to return to navigation. See the
Rust tab of the TUI search walkthrough for matching and
clearing examples, or CLI And TUI Task Browser
for the sample binary's CLI commands.
List Tasks
genja task list
genja task list --output table
genja task list --output json
genja task list --output yaml
genja task list --output markdown
my_project_cli task list
my_project_cli task list --output table
my_project_cli task list --output json
my_project_cli task list --output yaml
my_project_cli task list --output markdown
my_project_cli task list
my_project_cli task list --output table
my_project_cli task list --output json
my_project_cli task list --output yaml
my_project_cli task list --output markdown
The default format is table. Table and Markdown lists are compact summaries
containing task ID, version, name, ID source, implementation language, execution mode, and
constructibility. They omit descriptions, connection plugins, processors,
retry metadata, and input schemas.
Language is assigned by discovery (Rust or Python) and is separate from
Source, which says whether the descriptor ID was generated or explicit.
Custom descriptor sources without language metadata show Unknown.
JSON and YAML lists include one { descriptor, language } record per task
implementation. The nested descriptor contains all canonical fields. Use
task describe to inspect one implementation or task docs to document all tasks.
What Does Constructible Mean?
CONSTRUCTIBLE reports whether the task registration includes a factory that
can create the task from JSON input in its source language. A factory turns
input into a task instance; it does not run the task.
yesmeans a construction factory is registered.nomeans the task can be discovered and inspected, but has no registered factory. Creation by task identity and JSON input is unavailable until the author registers one. Application code may still create the task directly.
JSON and YAML output express the same field as descriptor.constructible: true
or descriptor.constructible: false. A yes value does not guarantee valid input or successful
execution. See Constructible Descriptor Field
for how Rust task structs and registration determine this value.
Describe A Task
Pass an identity in <task-id>@<task-version> form:
genja task describe acme.examples.backup_config@1.0.0
genja task describe acme.examples.backup_config@1.0.0 --output table
genja task describe acme.examples.backup_config@1.0.0 --output json
genja task describe acme.examples.backup_config@1.0.0 --output yaml
genja task describe acme.examples.backup_config@1.0.0 --output markdown
my_project_cli task describe acme.examples.backup_config@1.0.0
my_project_cli task describe acme.examples.backup_config@1.0.0 --output table
my_project_cli task describe acme.examples.backup_config@1.0.0 --output json
my_project_cli task describe acme.examples.backup_config@1.0.0 --output yaml
my_project_cli task describe acme.examples.backup_config@1.0.0 --output markdown
my_project_cli task describe rust:acme.examples.backup_config@1.0.0
my_project_cli task describe python:acme.examples.backup_config@1.0.0
my_project_cli task describe python:acme.examples.backup_config@1.0.0 --output json
my_project_cli task describe python:acme.examples.backup_config@1.0.0 --output yaml
my_project_cli task describe python:acme.examples.backup_config@1.0.0 --output markdown
Use the exact ID and version shown in the list. Explicit IDs, such as
acme.examples.backup_config, and generated IDs, such as
auto:my_project::tasks::BackupTask, can both be described. Preserve the
auto: prefix, :: separators, and capitalization in generated Rust IDs:
my_project_cli task describe auto:my_project::tasks::BackupTask@0.1.0
If Rust and Python provide the same ID and version, prefix the identity with
rust: or python: to select one implementation, as shown in the Mixed tab.
An unqualified identity works when only one implementation matches. For a
generated Rust ID, the language prefix comes before auto:, as in
rust:auto:my_project::tasks::BackupTask@0.1.0. Explicit task IDs cannot
contain :, and custom sources should avoid IDs beginning rust: or python:
because those prefixes are reserved for CLI selection.
The default table view displays ID, version, name, description, ID source, language,
execution mode, connection plugin, processors, constructibility, retry metadata,
and input schema availability. Missing optional metadata is shown as -.
Retry metadata is shown as compact JSON when present.
When an input schema is available, the table view includes pretty-printed JSON below the field summary. Markdown includes the same metadata and a fenced JSON schema block. JSON and YAML include the schema within their nested descriptor.
Output Formats
task list and task describe accept these lowercase --output values:
| Format | task list |
task describe |
|---|---|---|
table (default) |
Compact task summary rows | Field/value summary with input schema below when available |
json |
Array of implementation records | One implementation record |
yaml |
Sequence of implementation records | One implementation record |
markdown |
Compact task summary table | Task heading, metadata table, and input schema block when available |
JSON and YAML wrap the existing TaskDescriptor serialization contract as
{ descriptor, language }. The descriptor retains optional metadata and input
schemas without a language field. The outer language is rust, python, or
null when a custom source cannot identify it. Read descriptor fields through
the descriptor key, for example descriptor.id. Markdown output is raw
Markdown text, not a rendered terminal view.
Generate A Task Catalogue
genja task docs
genja task docs --output markdown
my_project_cli task docs
my_project_cli task docs --output markdown
my_project_cli task docs
my_project_cli task docs --output markdown
task docs supports Markdown only, and uses it by default. For registered tasks,
it generates a document with a Task Catalogue heading, an index linking to the
summary and individual tasks, a summary table, and detailed per-task sections.
Each task section includes descriptor metadata and a fenced JSON input schema
when available. Index links include the language qualifier and point to distinct
sections when Rust and Python share an ID and version.
Unlike the compact task list --output markdown table, the catalogue summary
also includes descriptions. Use this command for complete task documentation.
Output Examples
Select a project setup to see output from the checkout fixtures. The Python and Rust tabs cover every output format. The mixed tab shows the combined list and language-qualified lookup when both implementations share an ID and version.
These examples use the configured Python task module
in genja/examples/python. Install genja-py[cli] in the selected Python
environment, then run from the repository root. If you use a Cargo-built
binary and that environment's interpreter is not python on PATH, pass
its path with --python.
Task list (table)
genja --pyproject genja/examples/python/pyproject.toml task list
ID | VERSION | NAME | SOURCE | LANGUAGE | MODE | CONSTRUCTIBLE
========================================================================================================
acme.examples.backup_config | 1.0.0 | backup_config | explicit | Python | blocking | yes
-----------------------------+---------+---------------+----------+----------+----------+---------------
acme.examples.collect_facts | 1.0.0 | collect_facts | explicit | Python | blocking | yes
Task list (raw Markdown)
genja --pyproject genja/examples/python/pyproject.toml task list --output markdown
| ID | Version | Name | Source | Language | Mode | Constructible |
|-------------------------------|---------|-----------------|------------|----------|------------|---------------|
| `acme.examples.backup_config` | `1.0.0` | `backup_config` | `explicit` | `Python` | `blocking` | yes |
| `acme.examples.collect_facts` | `1.0.0` | `collect_facts` | `explicit` | `Python` | `blocking` | yes |
Task details and input schema (table)
genja --pyproject genja/examples/python/pyproject.toml task describe acme.examples.backup_config@1.0.0
Task: python:acme.examples.backup_config@1.0.0
Field | Value
===================================================================
ID | acme.examples.backup_config
-------------------+-----------------------------------------------
Version | 1.0.0
-------------------+-----------------------------------------------
Name | backup_config
-------------------+-----------------------------------------------
Description | Backs up selected paths from a network device
-------------------+-----------------------------------------------
ID source | explicit
-------------------+-----------------------------------------------
Language | Python
-------------------+-----------------------------------------------
Execution mode | blocking
-------------------+-----------------------------------------------
Connection plugin | ssh
-------------------+-----------------------------------------------
Processors | -
-------------------+-----------------------------------------------
Constructible | yes
-------------------+-----------------------------------------------
Retry | -
-------------------+-----------------------------------------------
Input schema | available
Input schema:
{
"properties": {
"backup_path": {
"type": "string"
},
"compress": {
"type": "boolean"
}
},
"required": [
"backup_path",
"compress"
],
"type": "object"
}
Implementation record (JSON)
genja --pyproject genja/examples/python/pyproject.toml task describe acme.examples.backup_config@1.0.0 --output json
{
"descriptor": {
"id": "acme.examples.backup_config",
"id_source": "explicit",
"name": "backup_config",
"version": "1.0.0",
"description": "Backs up selected paths from a network device",
"execution_mode": "blocking",
"connection_plugin_name": "ssh",
"processor_names": [],
"retry": null,
"input_schema": {
"properties": {
"backup_path": {
"type": "string"
},
"compress": {
"type": "boolean"
}
},
"required": [
"backup_path",
"compress"
],
"type": "object"
},
"constructible": true
},
"language": "python"
}
Implementation record (YAML)
genja --pyproject genja/examples/python/pyproject.toml task describe acme.examples.backup_config@1.0.0 --output yaml
descriptor:
id: acme.examples.backup_config
id_source: explicit
name: backup_config
version: 1.0.0
description: Backs up selected paths from a network device
execution_mode: blocking
connection_plugin_name: ssh
processor_names: []
retry: null
input_schema:
properties:
backup_path:
type: string
compress:
type: boolean
required:
- backup_path
- compress
type: object
constructible: true
language: python
Complete two-task catalogue (raw Markdown)
genja --pyproject genja/examples/python/pyproject.toml task docs
# Task Catalogue
## Index
- [Summary](#summary)
- [Tasks](#tasks)
- [`python:acme.examples.backup_config@1.0.0`](#task-acme-examples-backup-config-1-0-0-python-1)
- [`python:acme.examples.collect_facts@1.0.0`](#task-acme-examples-collect-facts-1-0-0-python-2)
## Summary
| ID | Version | Name | Source | Language | Mode | Constructible | Description |
|-------------------------------|---------|-----------------|------------|----------|------------|---------------|-----------------------------------------------|
| `acme.examples.backup_config` | `1.0.0` | `backup_config` | `explicit` | `Python` | `blocking` | yes | Backs up selected paths from a network device |
| `acme.examples.collect_facts` | `1.0.0` | `collect_facts` | `explicit` | `Python` | `blocking` | yes | Collects basic host facts |
## Tasks
<a id="task-acme-examples-backup-config-1-0-0-python-1"></a>
### python:acme.examples.backup_config@1.0.0
| Field | Value |
|-------------------|-----------------------------------------------|
| ID | `acme.examples.backup_config` |
| Version | `1.0.0` |
| Name | `backup_config` |
| Description | Backs up selected paths from a network device |
| ID source | `explicit` |
| Language | `Python` |
| Execution mode | `blocking` |
| Connection plugin | `ssh` |
| Processors | - |
| Constructible | yes |
| Retry | - |
| Input schema | available |
#### Input Schema
```json
{
"properties": {
"backup_path": {
"type": "string"
},
"compress": {
"type": "boolean"
}
},
"required": [
"backup_path",
"compress"
],
"type": "object"
}
```
<a id="task-acme-examples-collect-facts-1-0-0-python-2"></a>
### python:acme.examples.collect_facts@1.0.0
| Field | Value |
|-------------------|-------------------------------|
| ID | `acme.examples.collect_facts` |
| Version | `1.0.0` |
| Name | `collect_facts` |
| Description | Collects basic host facts |
| ID source | `explicit` |
| Language | `Python` |
| Execution mode | `blocking` |
| Connection plugin | - |
| Processors | - |
| Constructible | yes |
| Retry | - |
| Input schema | - |
These examples were generated from the registered task in
genja/examples/task_discovery_cli.rs. It is a documentation fixture, not a
backup implementation. The task has an explicit ID, retry metadata, and an
input schema; other tasks may have different or absent metadata.
Reproduce the output from this repository's root:
cargo run -p genja --features genja-cli --example task_discovery_cli -- task list
cargo run -p genja --features genja-cli --example task_discovery_cli -- task describe acme.examples.backup_config@1.0.0 --output json
cargo run -p genja --features genja-cli --example task_discovery_cli -- task docs
The examples below use my_project_cli as the executable name to match the
rest of this guide. Replace the arguments after -- in the Cargo command to
reproduce each format. All displayed outputs are complete for this one-task
fixture. JSON and YAML list commands wrap the implementation record in an array
or sequence.
Compact task list (table)
my_project_cli task list
ID | VERSION | NAME | SOURCE | LANGUAGE | MODE | CONSTRUCTIBLE
=====================================================================================================
acme.examples.backup_config | 1.0.0 | backup_config | explicit | Rust | async | yes
Compact task list (raw Markdown)
my_project_cli task list --output markdown
| ID | Version | Name | Source | Language | Mode | Constructible |
|-------------------------------|---------|-----------------|------------|----------|---------|---------------|
| `acme.examples.backup_config` | `1.0.0` | `backup_config` | `explicit` | `Rust` | `async` | yes |
Task details and input schema (table)
my_project_cli task describe acme.examples.backup_config@1.0.0
Task: rust:acme.examples.backup_config@1.0.0
Field | Value
====================================================================
ID | acme.examples.backup_config
-------------------+------------------------------------------------
Version | 1.0.0
-------------------+------------------------------------------------
Name | backup_config
-------------------+------------------------------------------------
Description | Backs up selected paths from a network device
-------------------+------------------------------------------------
ID source | explicit
-------------------+------------------------------------------------
Language | Rust
-------------------+------------------------------------------------
Execution mode | async
-------------------+------------------------------------------------
Connection plugin | ssh
-------------------+------------------------------------------------
Processors | -
-------------------+------------------------------------------------
Constructible | yes
-------------------+------------------------------------------------
Retry | {"allow":true,"max_attempts":3,"delay_ms":250}
-------------------+------------------------------------------------
Input schema | available
Input schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"backup_path": {
"type": "string"
},
"compress": {
"type": "boolean"
}
},
"required": [
"backup_path",
"compress"
],
"title": "BackupConfig",
"type": "object"
}
Implementation record (JSON)
my_project_cli task describe acme.examples.backup_config@1.0.0 --output json
{
"descriptor": {
"id": "acme.examples.backup_config",
"id_source": "explicit",
"name": "backup_config",
"version": "1.0.0",
"description": "Backs up selected paths from a network device",
"execution_mode": "async",
"connection_plugin_name": "ssh",
"processor_names": [],
"retry": {
"allow": true,
"max_attempts": 3,
"delay_ms": 250
},
"input_schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"backup_path": {
"type": "string"
},
"compress": {
"type": "boolean"
}
},
"required": [
"backup_path",
"compress"
],
"title": "BackupConfig",
"type": "object"
},
"constructible": true
},
"language": "rust"
}
Implementation record (YAML)
my_project_cli task describe acme.examples.backup_config@1.0.0 --output yaml
descriptor:
id: acme.examples.backup_config
id_source: explicit
name: backup_config
version: 1.0.0
description: Backs up selected paths from a network device
execution_mode: async
connection_plugin_name: ssh
processor_names: []
retry:
allow: true
max_attempts: 3
delay_ms: 250
input_schema:
$schema: https://json-schema.org/draft/2020-12/schema
properties:
backup_path:
type: string
compress:
type: boolean
required:
- backup_path
- compress
title: BackupConfig
type: object
constructible: true
language: rust
Complete one-task catalogue (raw Markdown)
my_project_cli task docs
# Task Catalogue
## Index
- [Summary](#summary)
- [Tasks](#tasks)
- [`rust:acme.examples.backup_config@1.0.0`](#task-acme-examples-backup-config-1-0-0-rust-1)
## Summary
| ID | Version | Name | Source | Language | Mode | Constructible | Description |
|-------------------------------|---------|-----------------|------------|----------|---------|---------------|-----------------------------------------------|
| `acme.examples.backup_config` | `1.0.0` | `backup_config` | `explicit` | `Rust` | `async` | yes | Backs up selected paths from a network device |
## Tasks
<a id="task-acme-examples-backup-config-1-0-0-rust-1"></a>
### rust:acme.examples.backup_config@1.0.0
| Field | Value |
|-------------------|--------------------------------------------------|
| ID | `acme.examples.backup_config` |
| Version | `1.0.0` |
| Name | `backup_config` |
| Description | Backs up selected paths from a network device |
| ID source | `explicit` |
| Language | `Rust` |
| Execution mode | `async` |
| Connection plugin | `ssh` |
| Processors | - |
| Constructible | yes |
| Retry | `{"allow":true,"max_attempts":3,"delay_ms":250}` |
| Input schema | available |
#### Input Schema
```json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"backup_path": {
"type": "string"
},
"compress": {
"type": "boolean"
}
},
"required": [
"backup_path",
"compress"
],
"title": "BackupConfig",
"type": "object"
}
```
The task browser example
links Rust tasks and loads the configured Python module. The command below
shows an in-project PDM virtual environment on Linux/macOS. Install
genja-py in the selected Python environment first. Replace the
--python path with that environment's interpreter if you use another
package manager, a different environment name such as venv, or a
different operating system. For PDM, run pdm info --python from
genja-core-python to find the path.
The Rust CollectFacts task in genja/examples/task_browser.rs has no
explicit registration. Its generated task version comes from the version
field in genja/Cargo.toml. The output below shows 0.5.0 for the
v0.5.0 release.
Combined task list (table)
cargo run -p genja --features genja-cli --example task_browser -- \
--python genja-core-python/.venv/bin/python \
--pyproject genja/examples/python/pyproject.toml task list
ID | VERSION | NAME | SOURCE | LANGUAGE | MODE | CONSTRUCTIBLE
=============================================================================================================
acme.examples.backup_config | 1.0.0 | backup_config | explicit | Rust | blocking | yes
---------------------------------+---------+---------------+-----------+----------+----------+---------------
acme.examples.backup_config | 1.0.0 | backup_config | explicit | Python | blocking | yes
---------------------------------+---------+---------------+-----------+----------+----------+---------------
acme.examples.collect_facts | 1.0.0 | collect_facts | explicit | Python | blocking | yes
---------------------------------+---------+---------------+-----------+----------+----------+---------------
auto:task_browser::CollectFacts | 0.5.0 | collect_facts | generated | Rust | async | no
Combined task list (raw Markdown)
cargo run -p genja --features genja-cli --example task_browser -- \
--python genja-core-python/.venv/bin/python \
--pyproject genja/examples/python/pyproject.toml task list --output markdown
| ID | Version | Name | Source | Language | Mode | Constructible |
|-----------------------------------|---------|-----------------|-------------|----------|------------|---------------|
| `acme.examples.backup_config` | `1.0.0` | `backup_config` | `explicit` | `Rust` | `blocking` | yes |
| `acme.examples.backup_config` | `1.0.0` | `backup_config` | `explicit` | `Python` | `blocking` | yes |
| `acme.examples.collect_facts` | `1.0.0` | `collect_facts` | `explicit` | `Python` | `blocking` | yes |
| `auto:task_browser::CollectFacts` | `0.5.0` | `collect_facts` | `generated` | `Rust` | `async` | no |
Selecting a shared identity
An unqualified lookup fails because both languages provide the identity:
my_project_cli task describe acme.examples.backup_config@1.0.0
error: task descriptor `acme.examples.backup_config@1.0.0` has implementations in multiple languages: Rust, Python; use `rust:acme.examples.backup_config@1.0.0` or `python:acme.examples.backup_config@1.0.0`
Use the language prefix to select one implementation:
my_project_cli task describe rust:acme.examples.backup_config@1.0.0
my_project_cli task describe python:acme.examples.backup_config@1.0.0
Exporting Task Descriptors (All Projects)
Commands write results to stdout. Use your shell's > redirection to save them
to a file; Genja does not provide an output-file option. Select the tab matching
your project; each example assumes its executable is on PATH.
JSON And YAML
Export implementation records, each with a complete descriptor and its language, for automation or later processing:
genja task list --output json > tasks.json
genja task list --output yaml > tasks.yaml
my_project_cli task list --output json > tasks.json
my_project_cli task list --output yaml > tasks.yaml
my_project_cli task list --output json > tasks.json
my_project_cli task list --output yaml > tasks.yaml
Export one implementation record, including any input schema in its descriptor, using its listed identity:
genja task describe acme.examples.backup_config@1.0.0 --output json > backup-config.json
genja task describe acme.examples.backup_config@1.0.0 --output yaml > backup-config.yaml
my_project_cli task describe acme.examples.backup_config@1.0.0 --output json > backup-config.json
my_project_cli task describe acme.examples.backup_config@1.0.0 --output yaml > backup-config.yaml
my_project_cli task describe python:acme.examples.backup_config@1.0.0 --output json > backup-config.json
my_project_cli task describe python:acme.examples.backup_config@1.0.0 --output yaml > backup-config.yaml
Markdown Documents
Choose the command according to how much detail the document needs:
| Command | Document contents |
|---|---|
task list --output markdown |
Compact summary table without descriptions or input schemas |
task describe <identity> --output markdown |
One task's metadata and input schema, when available |
task docs |
Catalogue index, summary including descriptions, and detailed sections for all tasks |
genja task list --output markdown > task-summary.md
genja task describe acme.examples.backup_config@1.0.0 --output markdown > backup-config.md
genja task docs --output markdown > task-catalog.md
my_project_cli task list --output markdown > task-summary.md
my_project_cli task describe acme.examples.backup_config@1.0.0 --output markdown > backup-config.md
my_project_cli task docs --output markdown > task-catalog.md
my_project_cli task list --output markdown > task-summary.md
my_project_cli task describe python:acme.examples.backup_config@1.0.0 --output markdown > backup-config.md
my_project_cli task docs --output markdown > task-catalog.md
The files contain raw Markdown. Use a Markdown renderer with table and fenced code-block support, such as GitHub or a suitably configured Zensical/MkDocs site, to display them. Catalogue navigation also depends on the renderer preserving heading links and the generated HTML anchors.
For Confluence, check the import or conversion workflow supported by your editor and installed apps. Markdown formatting shortcuts are not a guarantee that a complete pasted Markdown catalogue will be converted correctly. Atlassian documents Markdown shortcuts separately from legacy-editor markup insertion. Check tables, code blocks, and navigation links after importing. Genja generates the document; it does not publish it to Confluence or another platform.
Redirection Behaviour
The shell creates or overwrites the target file when using >, even if the
command later fails. Errors remain on stderr, so check the command's exit status
before treating a generated file as a successful export. Avoid combining stderr
with stdout when producing JSON or YAML for a parser.
These redirection examples also work with an executable on PATH in PowerShell
or cmd.exe. For an executable in the current directory, use ./my_project_cli
on Linux/macOS, .\my_project_cli.exe in PowerShell, or my_project_cli.exe in
cmd.exe. Output-file encoding is controlled by your shell; ensure UTF-8 when
passing files between tools or platforms.
For compiled Rust tasks, rebuild the project binary after changing task registrations, then regenerate the files. Python task modules are imported on each discovery command.
Discovery Scope And Architecture (All Projects)
The CLI reads Rust registrations linked into the running executable and Python
registrations from modules declared in [tool.genja.tasks] in the selected
pyproject.toml. It does not scan directories, build another project, or load
another executable's Rust registry. If expected Rust tasks are missing, check
that the project-specific binary links the task crate or modules.
Commands consume the shared TaskDescriptorSource abstraction from
genja_cli::discovery. It returns TaskImplementation records that pair each
canonical TaskDescriptor with source-assigned language metadata, or a common
DiscoveryError. The compiled source is backed by the registry in
genja-core; the combined source adds configured Python descriptors through
the genja-py helper. Existing custom sources that only return descriptors
remain compatible and have unknown language.
The command handlers pass implementations to separate output renderers. The combined source orders them deterministically by ID, version, and language. This boundary allows future descriptor sources to reuse the command and rendering layers.
These commands inspect metadata only. A descriptor's constructible value
reports its registration capability; listing or describing it does not construct
or execute the task. Task execution is outside the initial CLI discovery scope.
The CLI selects combined discovery when [tool.genja.tasks] is present and
compiled Rust discovery otherwise. The Python helper imports the declared
modules and returns descriptor JSON to the combined source. For Python or mixed
projects, --pyproject and --python work before or after a task subcommand.
Provider manifests and MCP-backed discovery are future work.
Empty Results And Errors (All Projects)
Empty Registries
An empty registry is a successful result, with exit status 0:
| Command | Output when no tasks are registered |
|---|---|
task list or task list --output table |
No registered tasks found. |
task list --output json |
An empty array: [] |
task list --output yaml |
An empty sequence: [] |
task list --output markdown |
The summary table header and separator, with no task rows |
task docs |
A Task Catalogue heading followed by No registered tasks found. |
The generic installed genja binary may have no project task registrations.
Changing directories does not change which tasks are linked into it.
Invalid And Missing Identities
task describe requires exactly one @ separator, a non-empty task ID without
leading or trailing whitespace, and a semantic version. A missing version does
not select the latest version. Lookup matches the listed ID and version exactly,
including generated IDs with auto: prefixes, :: separators, and uppercase
type names.
For example, omitting @<version>:
genja task describe acme.examples.backup_config
my_project_cli task describe acme.examples.backup_config
my_project_cli task describe acme.examples.backup_config
produces this error on stderr and exits with status 1:
error: invalid task identity `acme.examples.backup_config`: identity must contain exactly one `@` separator
A valid identity with no matching descriptor also exits with status 1:
error: task descriptor `acme.examples.missing@1.0.0` was not found
Use task list with your project's executable to check the available IDs and
versions. An ID-only lookup is not supported by this command, even though the
shared error model can represent ambiguous versions for other discovery consumers.
Output Streams And Exit Status
Successful command output, including help and version information, goes to
stdout. Errors go to stderr as human-readable text, even when --output json
or --output yaml is selected; errors are not serialized descriptors.
| Outcome | Exit status |
|---|---|
| Successful discovery, including empty lists, or requested help/version | 0 |
| Invalid identity, missing descriptor, discovery source failure, or serialization failure | 1 |
| Invalid command arguments, such as an omitted identity argument or unsupported output format | 2 |
For example, task list --output xml is rejected with an argument error listing
the supported formats. task docs accepts only markdown.
Discovery source failures include the backend's reason, such as a registry
registration conflict. Command handlers complete discovery and rendering before
printing results, so these discovery and serialization failures do not emit a
partial descriptor document on stdout.
Project-Local CLI Binary (Rust And Mixed Projects)
For Rust or mixed projects with compiled task registrations, build a project-specific
binary that links your task crate and delegates command handling to
genja-cli.
Use a project-specific binary name instead of genja, for example:
my_project_cliacme_genjanetwork_tasks_cli
This avoids overwriting or shadowing a globally installed genja binary.
The command name comes from the Cargo binary target name. If a package has a
default src/main.rs binary and no explicit [[bin]] entry, Cargo uses the
package name from [package].name:
[package]
name = "my_project_cli"
Building or installing that package produces a my_project_cli executable.
You can override the executable name with an explicit [[bin]] target:
[package]
name = "my-project"
[[bin]]
name = "my_project_cli"
path = "src/bin/my_project_cli.rs"
In that case the package is still named my-project, but the executable is
named my_project_cli.
Through The Genja Feature
For projects already using genja, enable the optional genja-cli feature.
This feature is disabled by default and exposes the CLI library as genja::cli.
The feature is available from v0.5.0. Add it with:
cargo add genja@0.5.0 --features genja-cli
For development from a checkout, use a path dependency instead (replace the
path with the location of the genja crate in your checkout):
[dependencies]
genja = { path = "../genja/genja", features = ["genja-cli"] }
Add the entry point to your binary:
use my_project_tasks as _;
fn main() -> std::process::ExitCode {
genja::cli::run_main()
}
Direct CLI Dependency
A dedicated CLI wrapper package can depend directly on genja-cli without
depending on the full genja runtime. From v0.5.0, add it with:
cargo add genja-cli@0.5.0
For development from a checkout, use a path dependency:
[dependencies]
genja-cli = { path = "../genja/genja-cli" }
Then add a binary target that references the task crate and delegates to
genja_cli::run_main():
use my_project_tasks as _;
fn main() -> std::process::ExitCode {
genja_cli::run_main()
}
Link Your Tasks
In either example, replace my_project_tasks with your task crate and add it as
a dependency of the binary package. The use my_project_tasks as _; line
intentionally links the crate that contains #[genja_task] registrations.
If your tasks live in the binary crate, declare the task modules there. If they
live in the same package's library target, reference that library from the binary.
Both dependency options expose the same CLI library. Rust discovery sees tasks
linked into the running executable; configured Python modules are imported at
runtime. Adding a dependency or enabling the feature does not create a binary
entry point or install the generic genja command.
End users receive your project-built executable; they do not need to install
genja-cli separately.
Running Project-Local Discovery (Rust And Mixed Projects)
Run task discovery commands through the project-specific binary:
my_project_cli task list
my_project_cli task describe auto:my_project::tasks::BackupTask@0.1.0
my_project_cli task docs > task-catalog.md
Those commands inspect the Rust registrations linked into my_project_cli and,
when [tool.genja.tasks] is configured, the declared Python modules. Running
the generic genja binary instead would not see your project-linked Rust tasks.
Development Workflow (Rust And Mixed Projects)
During development, you can run the project-local binary through Cargo:
cargo run --bin my_project_cli -- task list
cargo run --bin my_project_cli -- task describe auto:my_project::tasks::BackupTask@0.1.0
cargo run --bin my_project_cli -- task docs
The -- separator matters. Arguments before -- are handled by Cargo.
Arguments after -- are passed to the project-local binary.
If the binary belongs to another package in a workspace, select the package as well:
cargo run -p my-project-cli --bin my_project_cli -- task list
Runtime Deployment (Rust And Mixed Projects)
For runtime deployments, build a project-local CLI binary during release or CI,
then deploy that executable to the target machine. The target machine does not
need Cargo if you deploy a prebuilt binary.
For mixed projects, also deploy the Python task modules and provide a selected
Python environment with genja-py installed; the binary imports those modules
when discovery runs.
Build the binary:
cargo build --release --bin my_project_cli
The output path depends on the platform:
| Platform | Example output |
|---|---|
| Linux/macOS | target/release/my_project_cli |
| Windows | target\release\my_project_cli.exe |
Copy that executable to a location that matches your deployment policy. The
only requirement is that users or automation invoke the project-built
executable, either by full path or through PATH.
Common install locations include:
| Platform | User-local option | System-wide option |
|---|---|---|
| Linux | ~/.local/bin |
/usr/local/bin |
| macOS | /usr/local/bin or ~/bin |
/usr/local/bin |
| Windows | %USERPROFILE%\.cargo\bin or another user directory on PATH |
C:\Program Files\<Project>\bin |
On Linux/macOS:
./my_project_cli task list
./my_project_cli task docs > task-catalog.md
On Windows PowerShell:
.\my_project_cli.exe task list
.\my_project_cli.exe task docs > task-catalog.md
On Windows cmd.exe:
my_project_cli.exe task list
my_project_cli.exe task docs > task-catalog.md
For local development, Cargo can build and install the binary for you:
cargo install --path . --bin my_project_cli
This is a development or build-machine convenience. Production servers do not need Cargo when you deploy the compiled executable.
Lower-Level Entrypoint (Rust API)
genja::cli::run_main() (with the feature) and genja_cli::run_main() (with a
direct dependency) are the same recommended helper for binary main functions.
It reads arguments from the current process and returns a
std::process::ExitCode.
For tests or embedded callers that need to provide their own arguments, use the
lower-level genja::cli::run(args) or genja_cli::run(args) function.