Trail Atlas
Trail Atlas is a command-line log for people and agents working with books, articles and other materials. Save an account such as "Vera Example: I opened the introduction", find it later, and correct it when needed. Atlas keeps the records in local JSON files.
Install
The package is trail-atlas. It installs the tatlas command:
pip install trail-atlas
Run this in a Python environment where you can install packages. Supported platforms need neither Rust nor uv. See other installation methods for platform requirements and source builds.
Save and read a record
The following example uses invented Vera Example data in a fresh temporary directory. Choose the setup line for your shell.
Bash on Linux or macOS:
ATLAS_DEMO_DIR="$(mktemp -d /tmp/vera-example-atlas.XXXXXX)"
PowerShell on Windows:
$ATLAS_DEMO_DIR = Join-Path ([IO.Path]::GetTempPath()) ("vera-example-atlas-" + [guid]::NewGuid())
Then run these commands in the same shell:
tatlas --data-dir "$ATLAS_DEMO_DIR" --json add --id vera-example-1 --material https://example.org/book --actor "Vera Example" --original "Vera Example: I opened the introduction."
tatlas --data-dir "$ATLAS_DEMO_DIR" --json get --id vera-example-1
add saves the record. get reads it back by ID. Both JSON results contain record.id set to vera-example-1 and record.revision set to 1.
--materialidentifies the book, article or other material by an exact URL or reference. Atlas does not fetch it or rewrite the reference.--actornames the person or agent who interacted with that material. This can be someone other than the caller.--originalstores the supplied statement word for word.
Only material and actor are required record fields. Saving a reference alone leaves the action unspecified. tatlas add --help explains the optional fields.
For real records, choose a fixed, absolute, private directory outside public code checkouts. Pass it as --data-dir every time. Later commands must use the same directory. Atlas creates the store on the first write; it does not detect repository boundaries. The example's temporary directory is for disposable data.
--json produces operation results on stdout and errors on stderr. Help remains text. Input comes from flags. --data-dir and --json work before or after the command name.
Records and marks
A record describes one interaction with a material. If Vera Example opens a book today and reads a chapter tomorrow, those can be two records with different IDs. Use add for another interaction and edit to correct an existing record. Choose and retain a new ID for each interaction so you can retry by ID. If you omit --id, Atlas generates one.
A mark describes a material's current priority. Use focus for materials to work on now, later for ones to revisit, or none to clear it. One material can have many records and at most one current mark. Marks can exist without records. Editing or deleting a record does not change the mark, and marks never change automatically.
Choose a command
| To | Use |
|---|---|
| Save another interaction | add |
| Find saved records | list |
| Read a record by ID | get |
| Correct a record or clear optional fields | edit |
| Delete a record's content | rm |
| Set or clear a material's mark | mark |
| Read material marks | marks |
Run tatlas COMMAND --help for the fields and a complete example of that command.
list puts the newest saved records first and omits deletion receipts. Filter by an exact reference with --material, or by a case-sensitive substring with --context. Add --state focus, --state later or --state none to filter by material marks. Omit --state for all records. none includes both never-marked and cleared materials. A record must match every supplied filter.
Change existing data
A revision identifies a saved version. Atlas increases it on each edit, deletion or mark update. --if-revision makes your command fail if the current revision differs from the one you read.
- Before
editorrm, useget --id IDand pass itsrecord.revision. - Before
mark, usemarks, find the exact material reference and pass that entry'srevision. Use0only when the material is absent. Clearing a mark increases its revision; it does not reset to0.
Record revisions and mark revisions are separate counters. If the revision has changed, Atlas rejects the write and returns current_revision. Read the current data and reconsider your change before trying again.
edit changes only the fields you supply. Repeat --clear FIELD to clear multiple optional fields. The record ID and recording time stay unchanged. rm removes the content but keeps an ID/revision deletion receipt that get can read. The deleted ID stays reserved. Deletion does not securely erase old filesystem blocks or backups.
Recover from an uncertain result
An error or missing response does not always mean the write failed. Check saved state before repeating a command.
| Command | What to do |
|---|---|
add with a retained ID |
Repeat the same ID and all the same fields. replayed: true confirms the revision-1 record without another write. Different fields, a later revision or a deleted record cause a conflict. |
add without a known ID |
Find it with list --material and get. Repeating add can create a duplicate. Several matching records leave the outcome unresolved until you identify yours. |
edit or mark |
Read get or marks and compare fields and revision with the intended change. Matching values alone do not prove which caller wrote them. |
rm |
Repeat with the same pre-deletion revision to confirm its receipt without another write, or read get. |
Exit codes are 0 for success, 1 for an operation or storage error, 2 for flag parsing errors and 3 for revision or ID conflicts.
Storage details
The store contains records/<id>.json, optional marks.json and .lock. Reads require an initialized store. Schema version 1 rejects unknown fields and invalid record identities. IDs use 1 to 64 lowercase ASCII letters, digits, hyphens or underscores; Windows device names are reserved on every platform. On Unix, Atlas creates private directories and files. Existing directory permissions remain the owner's responsibility.
Atlas generates recording time in UTC, stored as Unix milliseconds in recorded_at_ms. The optional --interaction-date describes when the interaction happened. It does not change list order. Equal recording times use ascending IDs.
Processes coordinate through an OS advisory lock. Readers hold a shared lock. Writers hold an exclusive lock while reading, checking revisions and replacing files. A writer writes a temporary file beside the destination, flushes and syncs it, then renames it atomically. Linux and macOS also sync the containing directory. Windows does not, so power loss can lose a recently completed rename. Process coordination and complete file replacement still apply. Tests cover process restarts and concurrent processes, not power loss.
Use a local filesystem with working advisory locks and atomic rename. Network filesystems and direct edits outside Atlas are outside this protocol. Malformed data fails visibly without automatic repair; lists fail without partial output.
The OS releases locks when processes die. Keep .lock in place. Leftover .atlas-* temporary files are ignored and may contain uncommitted data. Remove them only while no Atlas process is using the store.
Other installation methods
Ready-made packages cover Linux with glibc 2.28 or newer on x86_64 and ARM64, macOS 13 or newer on Intel and Apple silicon, and Windows x86_64. Other targets require a source build and have no native CI coverage.
With uv, use uv tool install trail-atlas. For one run, use uvx --from trail-atlas tatlas --help.
A source build needs current stable Rust and a native linker. This implementation was checked with Rust 1.98.1. Pip also needs these tools if no ready-made package matches the platform.
cargo build --locked --release
cargo install --locked --path .
The built executable is target/release/tatlas, or tatlas.exe on Windows. It has no server or network access.
Development
Read AGENTS.md and GOALS.md for repository rules. Check changes with:
cargo fmt --all -- --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked
python3 scripts/limits.py
Stage new files before running limits. The public-hygiene check reads staged blobs, so an unstaged edit cannot hide an unmarked staged fixture or missing ignore rule. Known path checks do not detect every personal fact; review data before committing. The optional pre-commit hook runs formatting and limits without changing Git hook configuration.
CI runs the checks on all five supported platforms, then builds and installs each wheel through pip, uv tool and uvx. One Linux job also builds and installs the source archive. The publisher uploads those same tested artifacts to PyPI; the GitHub release attaches them and SHA256SUMS. It does not rebuild packages. Rust SBOM generation is disabled because its metadata includes local build paths.
Publishing uses repository jointsome0-lgtm/atlas, workflow ci.yml and environment pypi. A tag vX.Y.Z must match Cargo.toml and Cargo.lock and point to a commit on main. The tag must also be allowed by the environment's deployment policy. Changes to publishing access require the owner's approval.
Map
examples/: Rust syntax checker used by the limits entrypoint.scripts/: Repository limits, distribution contents and installed CLI checks.src/: CLI parsing, presentation, record operations and JSON storage.tests/: Product and limits tests through executable boundaries.tests/support/: Temporary-store and subprocess helpers for CLI tests.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file trail_atlas-0.1.2.tar.gz.
File metadata
- Download URL: trail_atlas-0.1.2.tar.gz
- Upload date:
- Size: 20.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b97460f84393875049dc897ef41858016ebbeb37c40b294934aea5bbb2c215d
|
|
| MD5 |
ab2fcf97a0ee03e396b822bac3da5fcd
|
|
| BLAKE2b-256 |
42ea88a7789a8b392dbe7b4222470c78ae58ee311c282ab507571f78d31429ef
|
Provenance
The following attestation bundles were made for trail_atlas-0.1.2.tar.gz:
Publisher:
ci.yml on jointsome0-lgtm/atlas
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trail_atlas-0.1.2.tar.gz -
Subject digest:
3b97460f84393875049dc897ef41858016ebbeb37c40b294934aea5bbb2c215d - Sigstore transparency entry: 2809862700
- Sigstore integration time:
-
Permalink:
jointsome0-lgtm/atlas@37cd394dde14ecdd0ab49026708a1d079e19daa4 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/jointsome0-lgtm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@37cd394dde14ecdd0ab49026708a1d079e19daa4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file trail_atlas-0.1.2-py3-none-win_amd64.whl.
File metadata
- Download URL: trail_atlas-0.1.2-py3-none-win_amd64.whl
- Upload date:
- Size: 314.2 kB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8895234ca39923d43f9397be5720a63942c09646c43f121769c00d25019d2a42
|
|
| MD5 |
b20b4444f67af7aae670ec24a33db3ee
|
|
| BLAKE2b-256 |
0ad948bc9ee2889b16e70f32768f9935d52a29beadf164b3dfcc2fb3c47305c1
|
Provenance
The following attestation bundles were made for trail_atlas-0.1.2-py3-none-win_amd64.whl:
Publisher:
ci.yml on jointsome0-lgtm/atlas
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trail_atlas-0.1.2-py3-none-win_amd64.whl -
Subject digest:
8895234ca39923d43f9397be5720a63942c09646c43f121769c00d25019d2a42 - Sigstore transparency entry: 2809862760
- Sigstore integration time:
-
Permalink:
jointsome0-lgtm/atlas@37cd394dde14ecdd0ab49026708a1d079e19daa4 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/jointsome0-lgtm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@37cd394dde14ecdd0ab49026708a1d079e19daa4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file trail_atlas-0.1.2-py3-none-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: trail_atlas-0.1.2-py3-none-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 411.0 kB
- Tags: Python 3, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3d36b23bf03fdb6ff4aa282fc23a4bdef4884ffef5c0b92cb16b6241d6364260
|
|
| MD5 |
09798fbbc8bd7246208d18483fe696ff
|
|
| BLAKE2b-256 |
d1fafecc5173705b8bf6069f7f0b24c81051abcf4ec596a00ea7ef32e7b78414
|
Provenance
The following attestation bundles were made for trail_atlas-0.1.2-py3-none-manylinux_2_28_x86_64.whl:
Publisher:
ci.yml on jointsome0-lgtm/atlas
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trail_atlas-0.1.2-py3-none-manylinux_2_28_x86_64.whl -
Subject digest:
3d36b23bf03fdb6ff4aa282fc23a4bdef4884ffef5c0b92cb16b6241d6364260 - Sigstore transparency entry: 2809862799
- Sigstore integration time:
-
Permalink:
jointsome0-lgtm/atlas@37cd394dde14ecdd0ab49026708a1d079e19daa4 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/jointsome0-lgtm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@37cd394dde14ecdd0ab49026708a1d079e19daa4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file trail_atlas-0.1.2-py3-none-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: trail_atlas-0.1.2-py3-none-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 395.1 kB
- Tags: Python 3, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce38cdf5eab645233fe5cb26caf16bb8d649172516b941ee0518fa520e7ca444
|
|
| MD5 |
bcaa812525dc6a7e792078eb68e29342
|
|
| BLAKE2b-256 |
46aba57d371edf3899b1fe68c067e45c7f45ec46703cb4fa8cc11fe004f1f7ea
|
Provenance
The following attestation bundles were made for trail_atlas-0.1.2-py3-none-manylinux_2_28_aarch64.whl:
Publisher:
ci.yml on jointsome0-lgtm/atlas
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trail_atlas-0.1.2-py3-none-manylinux_2_28_aarch64.whl -
Subject digest:
ce38cdf5eab645233fe5cb26caf16bb8d649172516b941ee0518fa520e7ca444 - Sigstore transparency entry: 2809862826
- Sigstore integration time:
-
Permalink:
jointsome0-lgtm/atlas@37cd394dde14ecdd0ab49026708a1d079e19daa4 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/jointsome0-lgtm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@37cd394dde14ecdd0ab49026708a1d079e19daa4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file trail_atlas-0.1.2-py3-none-macosx_13_0_x86_64.whl.
File metadata
- Download URL: trail_atlas-0.1.2-py3-none-macosx_13_0_x86_64.whl
- Upload date:
- Size: 382.6 kB
- Tags: Python 3, macOS 13.0+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ccfe598dce1629d8694f26764060ae7e5926d5920f417e034cd844ab8e0400f
|
|
| MD5 |
7fda04a22f07e97d731804ff669a2714
|
|
| BLAKE2b-256 |
5335942f0a2538c49def0c9a33892501b7c7bc13bc4cddeebb51b5bbd880a537
|
Provenance
The following attestation bundles were made for trail_atlas-0.1.2-py3-none-macosx_13_0_x86_64.whl:
Publisher:
ci.yml on jointsome0-lgtm/atlas
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trail_atlas-0.1.2-py3-none-macosx_13_0_x86_64.whl -
Subject digest:
2ccfe598dce1629d8694f26764060ae7e5926d5920f417e034cd844ab8e0400f - Sigstore transparency entry: 2809862733
- Sigstore integration time:
-
Permalink:
jointsome0-lgtm/atlas@37cd394dde14ecdd0ab49026708a1d079e19daa4 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/jointsome0-lgtm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@37cd394dde14ecdd0ab49026708a1d079e19daa4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file trail_atlas-0.1.2-py3-none-macosx_13_0_arm64.whl.
File metadata
- Download URL: trail_atlas-0.1.2-py3-none-macosx_13_0_arm64.whl
- Upload date:
- Size: 356.4 kB
- Tags: Python 3, macOS 13.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
83aac3fa9fb9d6284b42f5e22d3c1b761de5616739f5d1258feaf9e7c0bcf2dd
|
|
| MD5 |
2f266407ee4277e94c19aaee1e70db31
|
|
| BLAKE2b-256 |
2167586f67d18ce599116be358c830c84162352cfa30e5d2ae8620b2244ac8fa
|
Provenance
The following attestation bundles were made for trail_atlas-0.1.2-py3-none-macosx_13_0_arm64.whl:
Publisher:
ci.yml on jointsome0-lgtm/atlas
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trail_atlas-0.1.2-py3-none-macosx_13_0_arm64.whl -
Subject digest:
83aac3fa9fb9d6284b42f5e22d3c1b761de5616739f5d1258feaf9e7c0bcf2dd - Sigstore transparency entry: 2809862788
- Sigstore integration time:
-
Permalink:
jointsome0-lgtm/atlas@37cd394dde14ecdd0ab49026708a1d079e19daa4 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/jointsome0-lgtm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@37cd394dde14ecdd0ab49026708a1d079e19daa4 -
Trigger Event:
push
-
Statement type: