juras.iobeta
Sign inStart free
Examples

Recipes for real agent workflows.

Copy-paste snippets that solve concrete problems with the juras.io API. Open one, drop in your API key, and run it.

Repo & codebash · /sessions, /grep

Grep a GitHub repo for TODOs

Clone a repo, push every text file into a session, then grep for any TODO or FIXME. Three calls; the workspace evaporates when the script exits.

#!/usr/bin/env bash
set -euo pipefail
KEY=$JURAS_KEY

git clone --depth 1 https://github.com/$1 /tmp/repo
cd /tmp/repo

# 1. Open a session with every text file in the repo
files=$(git ls-files | grep -Ev '\.(png|jpg|gif|woff2?|mp4)$' | head -2000)
args=$(for f in $files; do printf -- '-F "files=@%s;filename=%s" ' "$f" "$f"; done)
SES=$(eval curl -s -X POST "https://api.juras.io/api/v1/sessions" \
  -H "Authorization: Bearer $KEY" \
  -F "storage=memory" \
  $args | jq -r .id)

# 2. Grep for TODO / FIXME with regex
curl -sG "https://api.juras.io/api/v1/sessions/$SES/grep" \
  -H "Authorization: Bearer $KEY" \
  --data-urlencode "query=TODO|FIXME" \
  --data-urlencode "mode=regex" \
  -d "before_context=1" \
  | jq '.matches[] | "\(.relative_path):\(.line_number)"'
bash · /sessions, /grepEndpoint reference →
Agents & tracesnode · /sessions, /append, /grep

Stream agent traces and search them live

Pipe each agent step into /append as it happens, then grep the running session for failed tool calls. Lets you tail an agent loop in production without setting up Loki.

import http from "node:http";
const agent = new http.Agent({ keepAlive: true });
const headers = { Authorization: `Bearer ${process.env.JURAS_KEY}` };

// 1. Open a session with a long TTL so traces stick around
const form = new FormData();
form.set("ttl_minutes", "720");
const { id } = await fetch("https://api.juras.io/api/v1/sessions", {
  method: "POST", agent, headers, body: form,
}).then(r => r.json());

// 2. On every agent step, append a small trace file
agent_loop.on("step", async (step) => {
  const fd = new FormData();
  fd.set("files",
    new Blob([JSON.stringify(step, null, 2)], { type: "text/plain" }),
    `step-${step.id}.json`);
  await fetch(`https://api.juras.io/api/v1/sessions/${id}/append`,
    { method: "PUT", agent, headers, body: fd });
});

// 3. Tail-search for tool errors
setInterval(async () => {
  const url = new URL(`https://api.juras.io/api/v1/sessions/${id}/grep`);
  url.searchParams.set("query", '"status": "error"');
  const r = await fetch(url, { agent, headers }).then(r => r.json());
  if (r.total_matched) console.warn(`${r.total_matched} failed steps so far`);
}, 5000);
node · /sessions, /append, /grepEndpoint reference →
Repo & codepython · /sessions (s3), /grep

Index a codebase, then grep with regex

Persist a session to S3 so you can keep grepping the same codebase across multiple agent runs. The first call uploads everything; subsequent calls just hit /grep.

import os, glob, httpx

c = httpx.Client(
    base_url="https://api.juras.io",
    headers={"Authorization": f"Bearer {os.environ['JURAS_KEY']}"},
    timeout=60,
)

# 1. Persist the session in S3 — survives beyond TTL
files = [("files", (p, open(p, "rb")))
         for p in glob.glob("./project/**/*.py", recursive=True)]
res = c.post("/api/v1/sessions",
             data={"storage": "s3"}, files=files).json()
session_id = res["id"]
print("session:", session_id)

# 2. Regex grep for any class that subclasses BaseAgent
hits = c.get(f"/api/v1/sessions/{session_id}/grep", params={
    "query":          r"class\s+\w+\(BaseAgent\)",
    "mode":           "regex",
    "before_context": 2,
}).json()

for m in hits["matches"]:
    print(f"{m['relative_path']}:{m['line_number']}  {m['line_content']}")
python · /sessions (s3), /grepEndpoint reference →
Support & docspython · /sessions, /grep

Pull error context from support archives

Drop a folder of customer transcripts and runbooks into a session, then have an agent grep for the error code from a fresh ticket — get back the relevant lines plus surrounding context for the model's prompt.

import httpx, os

c = httpx.Client(
    base_url="https://api.juras.io",
    headers={"Authorization": f"Bearer {os.environ['JURAS_KEY']}"},
)

# 1. Upload archives + runbooks (paths preserved)
files = [
    ("files", ("archives/2025-q4.txt", open("archives/2025-q4.txt", "rb"))),
    ("files", ("archives/2026-q1.txt", open("archives/2026-q1.txt", "rb"))),
    ("files", ("runbooks/auth.md",     open("runbooks/auth.md",     "rb"))),
    ("files", ("runbooks/billing.md",  open("runbooks/billing.md",  "rb"))),
]
res = c.post("/api/v1/sessions", files=files).json()
session_id = res["id"]

def context_for(error_code: str) -> str:
    r = c.get(f"/api/v1/sessions/{session_id}/grep", params={
        "query":          error_code,
        "before_context": 4,
        "after_context":  4,
    }).json()
    chunks = []
    for m in r["matches"]:
        chunks.append(f"# {m['relative_path']}:{m['line_number']}\n{m['line_content']}")
    return "\n\n".join(chunks)

# 2. Use it as agent context
prompt = f"""A customer reports error E_AUTH_402.
Relevant material from our archives:

{context_for("E_AUTH_402")}

Draft a reply."""
python · /sessions, /grepEndpoint reference →
Opsbash · /append, /grep

Add docs to an existing workspace

Your agent already has a session full of source code; now the user pastes a new spec. Append it without rebuilding from scratch — the same session ID keeps working.

SES=$(cat .juras-session)   # set by an earlier POST /sessions

# 1. Add a new spec file to the running session
curl -X PUT "https://api.juras.io/api/v1/sessions/$SES/append" \
  -H "Authorization: Bearer $JURAS_KEY" \
  -F "files=@./SPEC-2026-04-payments.md;filename=SPEC-2026-04-payments.md"

# 2. Grep across both old code AND the new spec in one call
curl -G "https://api.juras.io/api/v1/sessions/$SES/grep" \
  -H "Authorization: Bearer $JURAS_KEY" \
  --data-urlencode "query=webhook_secret" \
  -d "before_context=2"
bash · /append, /grepEndpoint reference →
Agents & tracesnode · /grep

Build a "search this folder" agent tool

Wrap juras.io in a tool the LLM can call directly. The agent passes a query, the tool returns ranked snippets — no vector DB, no embeddings, no chunker to tune.

import http from "node:http";
const agent = new http.Agent({ keepAlive: true });
const headers = { Authorization: `Bearer ${process.env.JURAS_KEY}` };

export const grepTool = {
  name: "grep_workspace",
  description: "Search the agent's working directory. Supports regex.",
  parameters: {
    query:   { type: "string",  description: "What to search for." },
    mode:    { type: "string",  enum: ["plain", "regex", "fuzzy"], default: "plain" },
    context: { type: "number",  default: 2 },
  },
  async run({ query, mode, context }: Record<string, unknown>,
             { sessionId }: { sessionId: string }) {
    const url = new URL(
      `https://api.juras.io/api/v1/sessions/${sessionId}/grep`);
    url.searchParams.set("query", String(query));
    url.searchParams.set("mode",  String(mode ?? "plain"));
    url.searchParams.set("before_context", String(context ?? 2));
    url.searchParams.set("after_context",  String(context ?? 2));
    const { matches } = await fetch(url, { agent, headers }).then(r => r.json());
    return (matches as Record<string, unknown>[]).map(m => ({
      path: m.relative_path, line: m.line_number, snippet: m.line_content,
    }));
  },
};
node · /grepEndpoint reference →