> For the complete documentation index, see [llms.txt](https://docs.gitloom.cloud/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.gitloom.cloud/documentation/rust.md).

# Rust

```toml
[dependencies]
gitloom = { version = "0.4", features = ["openai"] }
```

Provider-agnostic core; the `openai` feature adds conversions for [async-openai](https://crates.io/crates/async-openai).

## The proxy

`exchange` is one call where the SDK does everything but the provider request — memory context and the compaction summary are folded into the window it hands your closure, and both turns are stored afterwards:

```rust
let client = Client::new(""); // reads GITLOOM_API_KEY
let mut conv = Conversation::create(&client, "chat-42", ConversationOptions {
    model: "gpt-4o".into(),
    summarize_server: true, // GitLoom's model writes compaction summaries
    ..Default::default()
}).await?;

let reply = conv.exchange(vec![Message::user("What camera do I own?")], |window| async move {
    let res = my_openai_call(window)              // async_openai CreateChatCompletionResponse
        .await
        .map_err(|e| gitloom::Error::Usage(e.to_string()))?;
    let usage = gitloom::openai::usage_of(&res);
    let text = res.choices.into_iter().next().and_then(|c| c.message.content).unwrap_or_default();
    Ok((Message::assistant(text), Some(usage)))
}).await?;
```

## Multimodal and media

```rust
conv.append(vec![Message {
    role: "user".into(),
    content: Content::Parts(vec![
        Part::text_part("what's in this photo?"),
        Part::image_data(b64, "image/png"), // uploaded transparently, stored by reference
    ]),
    ..Default::default()
}], None).await?;
```

## Branching, edits, titles

```rust
conv.rewind(6).await?;
conv.edit(4, Message::user("ask differently")).await?;
conv.edit_in_place(4, "[redacted]").await?;
conv.set_title("Camera shopping").await?;
```

## Recall, filtered and answered

```rust
client.remember(&[Message::user("I moved to Pune.")], None).await?;

// Ranked memories, no model call. Milliseconds.
let res = client.recall_with("what camera do I own", &RecallOptions {
    tiers: vec!["facts".into()],        // facts | incidents | rules | skills
    paths: vec!["facts/gear".into()],   // any directories
    tags: vec!["camera".into()],
    since: Some("2026-01-01".into()),
    min_score: Some(0.3),
    limit: Some(8),
    ..Default::default()
}).await?;
for m in &res.memories {
    println!("{:.2} {} {:?}\n{}", m.score, m.path, m.matched, m.content);
}

// One text answer from a fast model over that retrieval …
let summary = client.answer("what camera do I own", &Default::default()).await?;
// … or let a stronger model search the memory itself with tools.
let agentic = client.answer("which trip had the longest flight?", &RecallOptions {
    mode: Mode::Agentic,
    ..Default::default()
}).await?;
println!("{} {:?}", agentic.answer.unwrap(), agentic.trace);
```

Each entry is **one whole memory**, not a scattering of its sections — `content` is the full body and `sections` names the headings that matched. `score` is a calibrated relevance in `[0, 1]`, comparable across queries, so `min_score` means the same thing whatever was asked. `matched` says which arms produced it; matched only by `graph` is context that rode in beside a real match, and `via` names what pulled it in. Set `detail: Some("full".into())` for revision history, the last diff, relation snippets and cues.

Filters apply **inside every retrieval arm** server-side, so confining a query to a directory is a real boundary rather than a cut made after the fact.

`answer` is metered as a chat, not a read, and returns `Error::NoAnswer` rather than an empty string when the model finds nothing to say.

## Tags and when it happened

```rust
use std::time::SystemTime;
use gitloom::{NewMemory, RememberOptions};

// A conversation: the tags go on every memory drawn from it.
client.remember_with(&[Message::user("We shipped the beta today.")], &RememberOptions {
    tags: vec!["launch".into(), "team:core".into()],
    occurred_at: Some("2026-09-12T18:30:00".into()),   // when it happened,
    timezone: Some("Asia/Kolkata".into()),             // read in this zone
    ..Default::default()
}).await?;

// A memory already formed.
client.write(&[NewMemory {
    path: "incidents/ops/outage.md".into(),
    content: "The API was down for 40 minutes.".into(),
    tags: vec!["outage".into()],
    occurred_at: Some(SystemTime::now().into()),
    ..Default::default()
}], None).await?;
```

`occurred_at` is when the thing happened, not when it was written. It takes a `SystemTime` (sent as epoch seconds), an `i64` of epoch seconds, or a string sent as is: RFC 3339 with an offset, a date `YYYY-MM-DD` meaning that calendar day, or a datetime without an offset, read in `timezone`. `write` takes no zone, so give its times an offset or a date. `date` still works and is deprecated.

Tags are trimmed and lowercased: letters, digits, spaces and `- _ . : / # @`, at most 32 of 64 characters each. A refused one comes back as `Error::Api` with code `invalid_tag` and a message naming the field.

Every recalled memory carries `user_tags`, yours alone, lowercased and sorted rather than in the order you sent them; `tags` lists those first, then the inferred ones, also sorted. `created_at`, `updated_at`, `occurred_at` and `expires_at` are `Option<SystemTime>`. `occurred_source` says how `occurred_at` is known (`user`, `extracted`, `said` or `written`), and `occurred_precision` is `day` when only the date is known (held as noon UTC on it) or `instant`. The `created` and `updated` strings are deprecated.

## Listing without a question

```rust
use gitloom::{RecallOptions, TimeField};

// No query: every memory tagged "launch" that happened in September, newest first.
let res = client.recall_with("", &RecallOptions {
    tags: vec!["launch".into()],
    since: Some("2026-09-01".into()),
    until: Some("2026-09-30".into()),          // a date alone includes that whole day
    time_field: Some(TimeField::Occurred),     // Occurred | Created | Updated (the default)
    tz: Some("Asia/Kolkata".into()),
    ..Default::default()
}).await?;
```

With an empty query, `recall_with` lists every memory the filters match, newest first by `time_field`, each scored 1. It needs at least one of `tags`, `tags_all`, `since`, `until`, `tiers` or `paths`, and returns `Error::Usage` before sending anything otherwise. It takes `Mode::Raw` with no `rank`. With a query, the same filters narrow the search.

## Direct memory

`remember` has a model decide what a conversation holds. When you already know what a memory says and where it belongs, store it as written:

```rust
use gitloom::{NewMemory, TopicsOptions, TreeOptions};

client.topics(&TopicsOptions { like: Some("databas".into()), ..Default::default() }).await?;
client.write(&[NewMemory {
    path: "facts/people/maya.md".into(),       // the directory is the topic
    content: "Maya rides a bicycle to work.".into(),
    cues: vec!["how does Maya get around".into()],
    related: vec!["spouse: facts/people/sam.md".into()],
    ..Default::default()
}], None).await?;

// Seconds later, once the write has landed:
let m = client.get("facts/people/maya.md", None).await?;   // a file, or file.md#section
let toc = client.tree(&TreeOptions { path: Some("facts".into()), depth: Some(3), ..Default::default() }).await?;
let graph = client.graph(&Default::default()).await?;
client.forget(&["facts/people/maya.md"], None).await?;
```

`topics` lists the directories with their memory counts; check it before inventing a topic. `tree` is the table of contents and `graph` the relationships between memories. A path that does not end in `.md` is refused before anything is sent. `write` and `forget` are asynchronous like `remember`, and `forget` leaves earlier revisions in git history. Send writes in batches: one call is one commit round.

## Vocabulary and skills

```rust
// Teach abbreviations and domain terms. A recall for "k8s" then also finds
// memories written "kubernetes", and the definition comes back as `defined`.
client.learn_terms(&[Term {
    term: "kubernetes".into(),
    aliases: vec!["k8s".into(), "kube".into()],
    definition: Some("Container orchestration.".into()),
    ..Default::default()
}], None).await?;
client.lookup_term("k8s", None).await?;      // → Some(Term { term: "kubernetes", .. })
client.vocabulary(Some("kube"), None).await?;
client.forget_terms(&["kubernetes"], None).await?;

// Store how things are done; find the skill that fits a task.
client.store_skills(&[Skill {
    name: "Deploy to production".into(),
    topic: Some("ops".into()),
    description: Some("Ship a release.".into()),
    content: Some("## Steps\n1. Tag the release.\n2. `make deploy ENV=prod`".into()),
    triggers: vec!["how do I ship a release".into(), "deploy to prod".into()],
    ..Default::default()
}], None).await?;
let skills = client.find_skills("release the new build", &Default::default()).await?;
```

Skills are memories under the `skills/` tier, so a recall with `tiers: vec!["skills".into()]` reaches them too.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.gitloom.cloud/documentation/rust.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
