Metadata-Version: 2.4
Name: retrosage
Version: 0.4.3
Summary: A portable command-line client for Hindsight memory banks
Author-email: Raphael Bossek <raphael.bossek@videoclinic.de>
License-Expression: MIT
Project-URL: Repository, https://github.com/forgegod/retrosage
Project-URL: Issues, https://github.com/forgegod/retrosage/issues
Project-URL: Changelog, https://github.com/forgegod/retrosage/releases
Keywords: hindsight,memory,ai-agent,cli,backup
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Archiving :: Backup
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: ocr
Requires-Dist: ocrmypdf; extra == "ocr"
Provides-Extra: release
Requires-Dist: build; extra == "release"
Requires-Dist: twine; extra == "release"
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: code-review-graph<3,>=2.3.6; extra == "dev"
Requires-Dist: lefthook<3,>=2.1; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Requires-Dist: tomli; python_version < "3.11" and extra == "dev"
Requires-Dist: twine; extra == "dev"
Dynamic: license-file

<p align="center">
  <img src="https://raw.githubusercontent.com/forgegod/retrosage/main/assets/logo-1024.png" alt="Retrosage" width="720">
</p>

<p align="center">
  <a href="https://github.com/forgegod/retrosage"><img src="https://img.shields.io/badge/GitHub-forgegod%2Fretrosage-181717?logo=github" alt="GitHub"></a>
  <a href="https://pypi.org/project/retrosage/"><img src="https://img.shields.io/pypi/v/retrosage?logo=pypi&label=PyPI" alt="PyPI"></a>
</p>

Retrosage is a portable Python CLI for
[Hindsight](https://hindsight.vectorize.io/) memory banks. The published
package provides the `retrosage` command and has no runtime dependencies.
Optional local OCR support uses `ocrmypdf` when explicitly enabled.

## Install

Python 3.10 or newer is required. Install Retrosage from PyPI as an isolated
command with `uv`:

```sh
uv tool install retrosage
retrosage version
```

Or install it with `pip` in a virtual environment:

```sh
python3 -m venv ~/.venvs/retrosage
~/.venvs/retrosage/bin/python -m pip install retrosage
~/.venvs/retrosage/bin/retrosage version
```

The default package has no runtime dependencies. Install the optional OCR extra
only when local PDF OCR fallback is required:

```sh
uv tool install 'retrosage[ocr]'
# or: ~/.venvs/retrosage/bin/python -m pip install 'retrosage[ocr]'
```

## Development installation

When working from a repository checkout, choose whether the installed command
should track live source edits or behave like a fixed release build.

### Live edit mode (`--editable`)

```sh
git clone https://github.com/forgegod/retrosage.git
cd retrosage
uv tool install --editable .
```

The tool environment points back to `retrosage.py` in this checkout. Source
edits take effect on the next `retrosage` invocation without reinstalling. Use
this mode while developing or debugging Retrosage.

To include the optional local OCR integration in editable mode:

```sh
uv tool install --editable '.[ocr]'
```

### Snapshot mode (`--force --from .`)

```sh
uv tool install --force --from . retrosage
```

This builds and installs a regular package from the checkout. Later source
edits are invisible until the command is reinstalled, which makes snapshot
mode useful for testing the checkout as a release-like artifact.

### Direct source mode

```sh
python3 retrosage.py version
python3 retrosage.py --help
./retrosage --help
```

Direct mode creates no installed command and needs no virtual environment. It
is the fastest option for core CLI changes because the default implementation
uses only the Python standard library. Optional OCR still needs `ocrmypdf` in
the selected Python environment and its system dependencies.

### Choose an installation mode

| Goal | Command |
| --- | --- |
| Install the official PyPI release | `uv tool install retrosage` |
| Develop against live checkout edits | `uv tool install --editable .` |
| Test the checkout as a fixed package | `uv tool install --force --from . retrosage` |
| Run the checkout without installing | `python3 retrosage.py ...` |
| Return to the official release | `uv tool install --force retrosage` |

`--force` replaces an existing Retrosage tool environment. It can be omitted
for a clean first installation. For the full contributor environment with
pytest, build tools, and commit hooks, follow [DEVELOPMENT.md](DEVELOPMENT.md).

## First use after installation

These checks prove the installed command works before making authenticated
changes:

```sh
retrosage version
retrosage --help
TMPDIR=$(mktemp -d)
printf '# first import\n' > "$TMPDIR/note.md"
retrosage docs import --bank demo --directory "$TMPDIR" --dry-run
rm -rf "$TMPDIR"
```

For network commands, export the Hindsight API key and select a real bank:

```sh
export HINDSIGHT_API_KEY='your-api-key'
retrosage banks list
retrosage memory recall --bank bank-foo --query "What do we know?"
```

For source checkout setup, tests, and commit hooks, see
[Retrosage development](https://github.com/forgegod/retrosage/blob/main/DEVELOPMENT.md).
Maintainers should use the
[release guide](https://github.com/forgegod/retrosage/blob/main/docs/RELEASING.md)
for PyPI trusted-publisher setup and version releases.

## Credentials

| Variable | Purpose |
| --- | --- |
| `HINDSIGHT_API_KEY` | Default Hindsight API key. |
| `HINDSIGHT_API_KEY_PROD` | Example profile key selected with `--api-key HINDSIGHT_API_KEY_PROD`. |

The key is read from the named environment variable only. Every network
command requires it, including non-dry-run `docs import`, `docs sync`, and
`docs watch`. `--help`, `version`, and truthful local `--dry-run` paths do not
require credentials or contact the API.

## Banks

```sh
retrosage banks list
retrosage banks create --bank bank-foo --name "Bank Foo"
retrosage banks get --bank bank-foo
retrosage banks update --bank bank-foo --retain-config config.json
retrosage banks stats --bank bank-foo --refresh
retrosage banks config --bank bank-foo --overrides-only
retrosage banks config-set --bank bank-foo --updates config.json
retrosage banks set-disposition --bank bank-foo --skepticism 3 --literalism 3 --empathy 4
retrosage banks consolidate --bank bank-foo
retrosage banks template-export --bank bank-foo
retrosage banks delete --bank bank-foo --yes
```

## Documents

```sh
retrosage docs import --bank bank-foo --file notes.pdf
retrosage docs import --bank bank-foo --directory ./documents
retrosage docs import --bank bank-foo --dir ./documents
retrosage docs import --bank bank-foo --directory ./documents \
  --extraction-mode iris --ocr-fallback auto
retrosage docs import --bank bank-foo --directory ./documents --dry-run
retrosage docs list --bank bank-foo --query report --tag current --all
retrosage docs get --bank bank-foo --document-id doc_123
retrosage docs update --bank bank-foo --document-id doc_123 --tag current
retrosage docs delete --bank bank-foo --document-id doc_123 --yes
retrosage docs sync --bank bank-foo --directory ./documents
retrosage docs sync --bank bank-foo --directory ./documents --dry-run
retrosage docs sync --bank bank-foo --directory ./documents --state ./sync-state.json --no-recursive
retrosage docs watch --bank bank-foo --directory ./documents --interval 10
retrosage docs watch --bank bank-foo --directory ./documents --dry-run
```

`docs import` accepts a single `--file` or a `--directory`. `--dir` is
an alias for `--directory` on this subcommand only; `docs sync` and
`docs watch` keep the canonical `--directory` flag. Directory mode
follows symlinked directories, including cloud-storage junctions, and uploads
every supported file in one pass. It does **not** keep a
manifest, so a re-run can create duplicate bank documents; for
incremental, retryable uploads, use `docs sync` or `docs watch`.

`--extraction-mode {iris,markitdown,markdown,default,concise,bank}`
switches the bank's `retain_extraction_mode` via PATCH for the
duration of the run (read-modify-write) and restores the previous value
on exit. Pass `--no-restore-extraction-mode` to leave the bank in the
chosen mode. The default value `bank` is a no-op so the legacy CLI
behaviour is unchanged. `--extraction-mode` paired with `--no-poll` is
rejected unless `--no-restore-extraction-mode` is also passed (PATCH +
no-polling would silently leave the bank changed). Use
`--raw-extraction-mode <value>` for arbitrary strings the backend
accepts beyond the curated choices.

`--ocr-fallback {off,auto,force}` handles PDFs the backend cannot
extract. `off` (default) is the legacy behaviour. `force` OCRs every
PDF locally before upload. `auto` tries once, then OCRs only the files
the backend rejects. `--ocr-engine {ocrmypdf,auto}` (default `auto`) uses `ocrmypdf` through
its Python module or CLI. OCR output is temporary and always removed after
upload. Direct `tesseract` PDF mode is intentionally unsupported because it
cannot reliably consume PDFs and produce the required upload artifact.

`--no-recursive` scans only the top level; `--dry-run` lists what would
be uploaded (with the requested `extraction_mode` and `ocr_fallback`)
without contacting the API or PATCHing the bank. `--dry-run` does not
require `HINDSIGHT_API_KEY`.

Errors are reported per-file; the partial result is still printed and
the exit code is `2` if any file failed. Progress lines are emitted on
`stderr` (suppress with `--quiet`).

`docs sync` keeps a manifest at `<directory>/.hindsight-sync.json`
(overridable with `--state`). Files are identified by relative path, size,
and `mtime_ns`; the manifest also stores the per-file SHA-256 for auditing.
Removed files are dropped from the manifest only — the CLI does not delete
their remote counterparts. Pass `--dry-run` to preview changes without
contacting the API. Global `--no-poll` is rejected for sync/watch because a
pending upload cannot safely advance the successful-upload manifest.

`docs watch` repeatedly runs `sync` at `--interval` seconds. It is implemented
as a polling loop (no kernel events) so it works on any platform. SIGINT and
SIGTERM request a clean shutdown between cycles; pass `--dry-run` to log
candidate changes without writing the manifest. The process exits `2` after
shutdown if any cycle failed.

`docs list` returns one page by default and supports `--query`, repeated `--tag`,
`--tags-match`, `--limit`, and `--offset`; `--all` follows every page. The pinned
API has no document date filters, so none are invented. `docs update` replaces
the full tag list; omitting `--tag` clears it.

## Memories

```sh
retrosage memory retain --bank bank-foo --text "The deployment is Friday" --tag release
retrosage memory retain --bank bank-foo --file note.txt --document-id note-1
printf '%s' "stdin memory" | retrosage memory retain --bank bank-foo --stdin
retrosage memory recall --bank bank-foo --query "When is deployment?" --budget mid --include-chunks
retrosage memory reflect --bank bank-foo --query "Summarize release risks" --include-facts
retrosage memory list --bank bank-foo --all
retrosage memory get --bank bank-foo --memory-id MEMORY_ID
retrosage memory history --bank bank-foo --memory-id MEMORY_ID
retrosage memory clear-observations --bank bank-foo --memory-id MEMORY_ID --yes
retrosage memory clear --bank bank-foo --fact-type observation --yes
```

`retain` requires exactly one explicit source: `--text`, a UTF-8 `--file`, or
`--stdin`. `recall` and `reflect` expose the confirmed simple tag, fact-type,
budget, and inclusion controls. `list` returns one explicit page by default;
`--all` follows pagination while preserving the first response's top-level
fields. Both clear commands require `--yes`; individual memory deletion is not
supported by the API and is intentionally absent.

## Operations And Diagnostics

```sh
retrosage operations list --bank bank-foo --all
retrosage operations list --bank bank-foo --status failed --task-type retain
retrosage operations get --bank bank-foo --operation-id OPERATION_ID --include-payload
retrosage operations cancel --bank bank-foo --operation-id OPERATION_ID --yes
retrosage operations retry --bank bank-foo --operation-id OPERATION_ID
retrosage health
retrosage api-version
```

Operation list filters are limited to the fields declared by the pinned API:
status, task type, pagination, and parent exclusion. `--all` follows pagination.
Cancellation requires `--yes`. Retry uses the same bounded polling and terminal
state handling as document and memory operations unless global `--no-poll` is
passed. `health` and `api-version` query the remote API; local `version` remains
offline. Metrics are intentionally absent because no practical hosted
automation use case is defined.

## Backup And Restore

```sh
retrosage backup --output backups/2026-06-30T09-30Z --bank bank-foo
retrosage backup --output backups/2026-06-30T09-30Z --include-observations
retrosage inspect --archive backups/2026-06-30T09-30Z/bank-foo
retrosage restore --archive backups/2026-06-30T09-30Z/bank-foo --bank bank-foo=bank-foo-copy
retrosage --no-poll restore --archive backups/2026-06-30T09-30Z/bank-foo --bank bank-foo=bank-foo-copy
```

## Globals

```sh
retrosage --api-base https://api.hindsight.vectorize.io --api-key HINDSIGHT_API_KEY banks list
retrosage --quiet banks get --bank bank-foo
```

`--poll-timeout` bounds total operation polling (default: 600 seconds).
`docs delete` requires `--yes`.

## License

Retrosage is available under the
[MIT License](https://github.com/forgegod/retrosage/blob/main/LICENSE).
