> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orcapods.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# README pass

> An agent that checks a README against the code it describes, and proposes an edit you approve before anything changes.

READMEs drift: a flag gets renamed, an install step stops working, an example uses an old function. This agent reads a snapshot of your repository, checks each claim in the README against the code, and proposes a corrected README. Your program shows you the diff and asks before it writes the file. If you say no, you tell the agent why and it tries again in the same session.

**You will use:** a [managed sandbox](/guides/environments#managed-sandbox), [uploaded files](/guides/files-and-artifacts#upload-a-file), and [artifacts](/guides/files-and-artifacts).

<Note>
  A managed sandbox uses [machine time](/plans#machine-time) while it runs and needs your plan's [minimum balance](/plans#paid-work-needs-a-minimum-balance) of Orca credit in your wallet.
</Note>

## How it works

The agent works on a copy in its sandbox and cannot touch your machine. The only way its edit reaches your files is through your program, after you approve it.

The rule that matters most is "with the file and line that proves it". It makes the agent check claims instead of rewriting prose it likes better, and it gives you something to verify.

## The program

Examples on this page assume the settings from the [shared setup](/recipes/overview#shared-setup). Run it from the root of a Git repository. It packs the committed files with `git archive`, so uncommitted changes and ignored files stay on your machine. Orca stages at most 16 MiB from one file, so the program stops if the compressed snapshot is bigger. For a large repository, archive only what the agent needs, for example `git archive --format=tar.gz HEAD README.md src`.

<Tabs>
  <Tab title="Python">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-black"}}
    """Propose README fixes and apply them only after you approve."""

    import os
    import subprocess
    from pathlib import Path

    import openai

    client = openai.OpenAI(api_key=os.environ["ORCA_API_KEY"], base_url=os.environ["ORCA_BASE_URL"])
    agents = client.beta.agents
    sessions = agents.sessions

    # Orca refuses to stage any one file over 16 MiB, however it was uploaded.
    STAGED_FILE_LIMIT = 16 * 1024 * 1024
    INSTRUCTIONS = """\
    You keep a README accurate. You work in a Linux sandbox with a shell.
    The repository is in /workspace/repo.tar.gz. Extract it to /workspace/repo if it is
    not there yet.
    Check every concrete claim in README.md against the code: commands, flags, config keys,
    file paths, function names, version numbers, and code examples.
    Fix only what is wrong or missing. Keep the author's structure and voice.
    Do not add marketing, badges, or sections nobody asked for.
    Create /workspace/outputs if it does not exist.
    Save the corrected file to /workspace/outputs/README.md, and save a list of each change,
    with the file and line in the code that proves it, to /workspace/outputs/changes.md.
    Reply with a one-paragraph summary. If the user rejects your edit, apply their
    feedback and save both files again. Do not use emojis."""
    README = Path("README.md")
    PROPOSED = Path("README.proposed.md")

    if not README.is_file():
        raise SystemExit("No README.md here. Run this from the root of a Git repository.")
    snapshot = subprocess.run(
        ["git", "archive", "--format=tar.gz", "HEAD"], check=True, capture_output=True,
    ).stdout
    if len(snapshot) > STAGED_FILE_LIMIT:
        raise SystemExit("Snapshot is over the 16 MiB limit for one staged file. Archive a subfolder instead.")


    def run_turn(session_id, text):
        """Send one message, wait for the turn, and return its status and the reply."""
        status = None
        with sessions.stream(session_id, input=text) as stream:
            for event in stream:
                if event.type == "agent.session.turn.completed":
                    status = event.turn.status
        for item in sessions.items.list(session_id, limit=20).data:
            if item.type == "message" and item.role == "assistant":
                return status, " ".join(p.text for p in item.content or [] if getattr(p, "text", None))
        return status, ""


    def newest(session_id, name):
        """The newest artifact with this file name, as text."""
        matches = [a for a in sessions.artifacts.list(session_id) if Path(a.path).name == name]
        if not matches:
            return None
        latest = max(matches, key=lambda a: a.created_at)
        return sessions.artifacts.content(latest.id, session_id=session_id).content.decode()


    def show_diff(proposed):
        """Print the proposed change as a diff."""
        PROPOSED.write_text(proposed)
        # git diff exits 1 when the files differ; the diff is already printed.
        subprocess.run(["git", "--no-pager", "diff", "--no-index", "--", str(README), str(PROPOSED)])
        PROPOSED.unlink()


    uploaded = agent = session = None
    try:
        uploaded = client.files.create(file=("repo.tar.gz", snapshot), purpose="user_data")
        agent = agents.create(model=os.environ["ORCA_MODEL"], name="readme-pass", instructions=INSTRUCTIONS)
        session = sessions.create(
            agent_id=agent.id,
            environment={
                "type": "openai_hosted",
                "network": {"access": "disabled"},
                "files": [{"type": "file_id", "file_id": uploaded.id, "path": "/workspace/repo.tar.gz"}],
            },
        )

        message = "Check README.md against the code and propose fixes."
        while True:
            status, reply = run_turn(session.id, message)
            proposed = newest(session.id, "README.md")
            if status != "completed" or proposed is None:
                raise SystemExit(f"No proposal (turn {status}): {reply}")

            print(reply, "\n", flush=True)
            if proposed == README.read_text():
                print("README.md is already accurate.")
                break
            show_diff(proposed)
            answer = input("Allow this edit? 1 Yes  2 No: ").strip()
            if answer == "1":
                README.write_text(proposed)
                Path("readme-changes.md").write_text(newest(session.id, "changes.md") or "")
                print("README.md updated. Evidence in readme-changes.md.")
                break
            message = "I rejected that edit. " + input("What should change? ")
    finally:
        # Delete each resource on its own, so one failed delete does not skip the rest.
        if session:
            try:
                sessions.delete(session.id)
            except openai.APIError:
                pass
        if agent:
            try:
                agents.delete(agent.id)
            except openai.APIError:
                pass
        if uploaded:
            try:
                client.files.delete(uploaded.id)
            except openai.APIError:
                pass
        client.close()
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":{"light":"vitesse-light","dark":"vitesse-black"}}
    /** Propose README fixes and apply them only after you approve. */
    import { execFileSync } from 'node:child_process';
    import { existsSync } from 'node:fs';
    import { readFile, unlink, writeFile } from 'node:fs/promises';
    import { basename } from 'node:path';
    import { createInterface } from 'node:readline/promises';
    import OpenAI from 'openai';

    const client = new OpenAI({ apiKey: process.env.ORCA_API_KEY!, baseURL: process.env.ORCA_BASE_URL! });
    const agents = client.beta.agents;
    const sessions = agents.sessions;

    // Orca refuses to stage any one file over 16 MiB, however it was uploaded.
    const STAGED_FILE_LIMIT = 16 * 1024 * 1024;
    const INSTRUCTIONS = `You keep a README accurate. You work in a Linux sandbox with a shell.
    The repository is in /workspace/repo.tar.gz. Extract it to /workspace/repo if it is
    not there yet.
    Check every concrete claim in README.md against the code: commands, flags, config keys,
    file paths, function names, version numbers, and code examples.
    Fix only what is wrong or missing. Keep the author's structure and voice.
    Do not add marketing, badges, or sections nobody asked for.
    Create /workspace/outputs if it does not exist.
    Save the corrected file to /workspace/outputs/README.md, and save a list of each change,
    with the file and line in the code that proves it, to /workspace/outputs/changes.md.
    Reply with a one-paragraph summary. If the user rejects your edit, apply their
    feedback and save both files again. Do not use emojis.`;

    if (!existsSync('README.md')) {
      console.error('No README.md here. Run this from the root of a Git repository.');
      process.exit(1);
    }
    const snapshot = execFileSync('git', ['archive', '--format=tar.gz', 'HEAD'], { maxBuffer: 512 * 1024 * 1024 });
    if (snapshot.length > STAGED_FILE_LIMIT) {
      console.error('Snapshot is over the 16 MiB limit for one staged file. Archive a subfolder instead.');
      process.exit(1);
    }

    /** Send one message, wait for the turn, and return its status and the reply. */
    async function runTurn(sessionId: string, text: string) {
      let status: string | undefined;
      for await (const event of sessions.stream(sessionId, { input: text })) {
        if (event.type === 'agent.session.turn.completed') status = event.turn.status;
      }
      for (const item of (await sessions.items.list(sessionId, { limit: 20 })).data as any[]) {
        if (item.type === 'message' && item.role === 'assistant') {
          return { status, reply: (item.content ?? []).map((p: any) => p.text).filter(Boolean).join(' ') };
        }
      }
      return { status, reply: '' };
    }

    /** The newest artifact with this file name, as text. */
    async function newest(sessionId: string, name: string) {
      let latest: { id: string; created_at: number } | undefined;
      for await (const artifact of sessions.artifacts.list(sessionId)) {
        if (basename(artifact.path) === name && (!latest || artifact.created_at > latest.created_at)) latest = artifact;
      }
      if (!latest) return undefined;
      return (await sessions.artifacts.content(latest.id, { session_id: sessionId })).text();
    }

    /** Print the proposed change as a diff. */
    async function showDiff(proposed: string) {
      await writeFile('README.proposed.md', proposed);
      try {
        execFileSync('git', ['--no-pager', 'diff', '--no-index', '--', 'README.md', 'README.proposed.md'], { stdio: 'inherit' });
      } catch {
        // git diff exits 1 when the files differ; the diff is already printed.
      }
      await unlink('README.proposed.md');
    }

    let uploaded: { id: string } | undefined;
    let agent: { id: string } | undefined;
    let session: { id: string } | undefined;
    const prompt = createInterface({ input: process.stdin, output: process.stdout });
    try {
      uploaded = await client.files.create({ file: new File([snapshot], 'repo.tar.gz'), purpose: 'user_data' });
      agent = await agents.create({ model: process.env.ORCA_MODEL!, name: 'readme-pass', instructions: INSTRUCTIONS });
      session = await sessions.create({
        agent_id: agent.id,
        environment: {
          type: 'openai_hosted',
          network: { access: 'disabled' },
          files: [{ type: 'file_id', file_id: uploaded.id, path: '/workspace/repo.tar.gz' }],
        },
      });

      let message = 'Check README.md against the code and propose fixes.';
      while (true) {
        const { status, reply } = await runTurn(session.id, message);
        const proposed = await newest(session.id, 'README.md');
        if (status !== 'completed' || proposed === undefined) throw new Error(`No proposal (turn ${status}): ${reply}`);

        console.log(reply, '\n');
        if (proposed === (await readFile('README.md', 'utf8'))) {
          console.log('README.md is already accurate.');
          break;
        }
        await showDiff(proposed);
        const answer = (await prompt.question('Allow this edit? 1 Yes  2 No: ')).trim();
        if (answer === '1') {
          await writeFile('README.md', proposed);
          await writeFile('readme-changes.md', (await newest(session.id, 'changes.md')) ?? '');
          console.log('README.md updated. Evidence in readme-changes.md.');
          break;
        }
        message = 'I rejected that edit. ' + (await prompt.question('What should change? '));
      }
    } catch (error) {
      console.error(error instanceof Error ? error.message : error);
      process.exitCode = 1;
    } finally {
      prompt.close();
      // Delete each resource on its own, so one failed delete does not skip the rest.
      if (session) await sessions.delete(session.id).catch(() => {});
      if (agent) await agents.delete(agent.id).catch(() => {});
      if (uploaded) await client.files.delete(uploaded.id).catch(() => {});
    }
    ```
  </Tab>
</Tabs>

Each turn's outputs become new artifacts and the old ones stay as they were, so `newest()` picks the latest copy by its creation time.

## Make it yours

* **Include more docs.** Name other files in the prompt, for example "also check docs/install.md and CONTRIBUTING.md", and have the agent save each one under `/workspace/outputs`.
* **Run it in CI.** Without the prompt, the same program can fail a build when the agent proposes any change, and attach `changes.md` to the job.
* **Open a pull request instead.** Write the proposal to a branch and open a pull request from your program, so the review happens where your team already reviews code.
* **Keep secrets out.** `git archive` only packs committed files. If secrets are committed, rotate them; do not send that snapshot.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.