libgrite-cli 0.5.3

Programmatic CLI library for grite: issue tracking, sync, and context management
Documentation

libgrite-cli

License: MIT Crates.io Documentation Build Status

Programmatic API for all Grite operations — embed issue tracking, task coordination, and distributed sync directly into your Rust applications.

libgrite-cli exposes every command the grite binary supports as a clean, composable library function. This makes it easy to build custom workflows, integrate issue tracking into existing applications, create multi-agent harnesses, or write automation scripts that interact with Grite repositories.

If you are building a Rust application that needs programmatic issue tracking, agent orchestration, or git-backed task management, this crate is your entry point.


What This Crate Provides

Complete Command Coverage

Every CLI command has a corresponding library function:

Module Operations
issue create, list, show, update, close, reopen, comment, label, assign, link, attach
actor init, list, show, set_default
sync pull, push, merge, snapshot, rebuild
context extract, query (tree-sitter symbol extraction)
lock acquire, release, status, list
daemon start, stop, status

Context Resolution

The GriteContext type handles all the complexity of finding repositories, resolving actors, and choosing execution modes (daemon vs. standalone):

use libgrite_cli::{GriteContext, ResolveOptions};

// Automatically resolves the git repo, actor, and execution mode
let ctx = GriteContext::resolve(&ResolveOptions::default())?;

GriteContext automatically:

  • Discovers the git repository from the current directory or ancestors
  • Loads the default actor configuration
  • Detects whether the daemon is running and prefers IPC when available
  • Falls back to standalone mode if the daemon is unavailable

Async Support

Enable the async feature for tokio-based wrappers around all sync operations:

[dependencies]
libgrite-cli = { version = "0.5", features = ["async"] }
use libgrite_cli::async_wrappers::issue_create_async;

// Run issue creation in a blocking task pool
let result = issue_create_async(ctx, options).await?;

Every sync function has an *_async counterpart that runs the operation in tokio::spawn_blocking, preventing event loop blocking during database operations.

Type-Safe Options

Every operation takes a dedicated options struct with strongly typed fields:

use libgrite_cli::IssueCreateOptions;

let options = IssueCreateOptions {
    title: "Refactor parser".into(),
    body: "Use nom instead of hand-rolled logic".into(),
    labels: vec!["tech-debt".into()],
    assignees: vec![],
    parent_issue: None,
};

This eliminates stringly-typed APIs and provides compile-time guarantees about which options are valid for which operations.


Key Modules

context

Repository and actor resolution:

use libgrite_cli::{GriteContext, ResolveOptions};

let ctx = GriteContext::resolve(&ResolveOptions {
    git_dir: Some("/path/to/.git".into()),
    actor_id: None, // Use default actor
})?;

issue

Full issue lifecycle management:

use libgrite_cli::{issue_create, issue_list, issue_show, IssueCreateOptions, IssueFilter};

// Create an issue
let result = issue_create(&ctx, &IssueCreateOptions {
    title: "Fix race condition".into(),
    body: "...".into(),
    labels: vec!["bug".into()],
    ..Default::default()
})?;

// List open issues
let issues = issue_list(&ctx, &IssueFilter::default().status(Status::Open))?;

// Show details
let issue = issue_show(&ctx, &result.issue_id)?;

actor

Multi-actor identity management:

use libgrite_cli::{actor_init, actor_list, actor_set_default};

// Initialize a new actor
let actor = actor_init(&ctx, "CI Runner")?;

// List all actors
let actors = actor_list(&ctx)?;

// Set default
actor_set_default(&ctx, &actor.id)?;

sync

Distributed synchronization:

use libgrite_cli::{sync_pull, sync_push, sync_rebuild};

// Pull remote changes
sync_pull(&ctx, "origin")?;

// Push local changes
sync_push(&ctx, "origin")?;

// Rebuild materialized view from WAL
sync_rebuild(&ctx, true)?; // true = from snapshot

lock

Distributed resource locking:

use libgrite_cli::{lock_acquire, lock_release};

// Claim exclusive access to a resource
lock_acquire(&ctx, "src/parser.rs", 3600)?; // TTL: 1 hour

// Release when done
lock_release(&ctx, "src/parser.rs")?;

async_wrappers

Tokio-compatible async variants:

use libgrite_cli::async_wrappers::{
    issue_create_async, issue_list_async, sync_pull_async,
};

let issues = issue_list_async(ctx.clone(), filter).await?;

Quick Example

use libgrite_cli::{
    GriteContext, ResolveOptions,
    IssueCreateOptions, IssueFilter,
    issue_create, issue_list,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Resolve context from the current directory
    let ctx = GriteContext::resolve(&ResolveOptions::default())?;

    // Create an issue
    let result = issue_create(&ctx, &IssueCreateOptions {
        title: "Refactor parser".into(),
        body: "Use nom instead of hand-rolled logic".into(),
        labels: vec!["tech-debt".into()],
        assignees: vec![],
        parent_issue: None,
    })?;

    println!("Created issue: {}", result.issue_id);

    // List all open issues
    let filter = IssueFilter::default()
        .status(Status::Open);
    let issues = issue_list(&ctx, &filter)?;

    println!("Open issues: {}", issues.len());
    for issue in &issues {
        println!("  - {}: {}", issue.id, issue.title);
    }

    Ok(())
}

Architecture

libgrite-cli (programmatic API)
  |
  +-- libgrite-core (data model, storage, CRDTs)
  +-- libgrite-git (WAL, sync, snapshots)
  +-- libgrite-ipc (daemon communication, optional)

The library abstracts over the underlying crates, providing a unified interface regardless of whether the daemon is running. When the daemon is available, operations are dispatched via IPC. When it is not, the library opens the database directly.


Why Use the Library Instead of the CLI?

For Application Developers

If you are building an application that needs issue tracking (a CI system, a project management tool, an agent harness), shelling out to the CLI is fragile:

  • Parsing output — You must parse human-readable output or JSON from stdout.
  • Error handling — Exit codes are coarse. You lose structured error information.
  • Performance — Every invocation pays process startup cost.
  • State management — You must manage working directory and environment variables.

The library gives you:

  • Native Rust types — Results are structs, not strings.
  • Rich errors — Every error variant is typed and carry context.
  • In-process execution — No process overhead. Direct function calls.
  • Composable — Build higher-level abstractions by combining library functions.

For Agent Harnesses

Multi-agent systems need to query and update issue state at high frequency:

// An agent harness can query issues, claim locks, and post updates
// without ever shelling out to a subprocess
loop {
    let tasks = issue_list_async(&ctx, todo_filter).await?;
    for task in tasks {
        if lock_acquire_async(ctx.clone(), &task.id, 3600).await.is_ok() {
            spawn_agent(task).await;
        }
    }
}

Configuration

Library behavior is controlled through ResolveOptions and environment variables:

Variable Description
GRITE_GIT_DIR Override the detected .git directory
GRITE_ACTOR_ID Override the default actor
GRITE_NO_DAEMON Force standalone mode (no IPC)

See Also


License

MIT License — see LICENSE for details.