TreeSift selects entries below one explicit filesystem root and either serializes the selection as ZIP/TAR/TAR.GZ or prepares it as an AI context handoff. Selection is independent from every consumer so archive writers, context planning, listing, and verification share the same ordered filesystem decisions.
The project intentionally avoids a plugin registry or provider framework. Two concrete backends are sufficient; another abstraction is justified only by a new, demonstrated variation point.
filesystem root
↓
HierarchicalGitIgnore + explicit policies
↓
select_tree → SelectionPlan
├── list / explain / JSON
├── ZIP writer
├── TAR writer
├── portability audit
└── Git export-ignore filter
├── archive inspection → manifest / verification
└── AI context planning
↓
ContextPlan
├── analysis / token tree
├── Markdown / JSON
├── split parts
└── snapshot manifest / delta
treesift.ignore: scoped ignore discovery, matching, precedence, andRuleDecisionexplanations.treesift.selection: traversal, classification, observed metadata,SelectionPlan, symlink policy, and portability audit.treesift.archive: ZIP serialization and the stablecreate_zipAPI.treesift.tar_archive: TAR/TAR.GZ serialization andcreate_tar.treesift.manifest: archive inspection, hashes, schema objects, and atomic sidecar writes.treesift.verification: structural and optional manifest comparison.treesift.config: explicit[tool.treesift]TOML loading.treesift.git_attributes: optional Gitexport-ignorefiltering.treesift.cli: argument parsing, configuration precedence, rendering, and stable exit codes.treesift._operation: shared low-level atomicity, metadata normalization, and strict-consistency helpers.treesift.context: AI-safe filtering, UTF-8/binary classification, measurements, Git provenance, deltas, token estimates, andContextPlan.treesift.context_render: deterministic Markdown/JSON rendering, splitting, context output hashing, and atomic context-manifest writes.treesift.sensitivity: intentionally small high-confidence sensitive-content detector set.treesift.targets: static, dated provider upload-limit profiles.
SelectedEntry carries the source path, archive path, entry kind, size, mode,
mtime, device, inode, ownership metadata, and optional symlink target observed
during traversal. Writers do not rediscover ignore rules and use the same member
ordering.
SelectionPlan is an observed view, not an immutable filesystem snapshot.
Strict mode compares identity and metadata before and after serialization to
detect common races.
For each candidate, rules are evaluated from <source>/.gitignore through each
ancestor directory. Every pattern receives a path relative to its containing
directory. The last matching decision wins. Explicit CLI/config exclusion rules
run last.
RuleDecision preserves the winning source, line, pattern, and complete match
history for --explain.
Automatically discovered symlinked .gitignore files are treated as data and
are not followed.
The selected source is the discovery boundary. Parent ignores, global Git
configuration, and .git/info/exclude are not loaded. An explicit config,
custom root ignore, or exclusion file is read only when requested.
Symlink targets are untrusted and never traversed. safe policy rejects
absolute and source-escaping targets; reject disallows all links.
Special files are rejected before opening. Archive verification rejects unsafe member names, duplicates, count-limit violations, and uncompressed-size limits without extracting data.
Each archive and manifest is written to a temporary sibling and committed with
os.replace. Existing destinations require overwrite authorization.
Temporary files and empty output directories created by failed operations are
cleaned up.
An archive and its sidecar manifest are two individually atomic outputs. The pair is not a filesystem transaction; consumers should publish both only after both operations succeed.
Normal mode preserves observed timestamps and metadata. Reproducible mode uses
an explicit timestamp, SOURCE_DATE_EPOCH, or a fixed fallback; uses UTC ZIP
time; normalizes file modes; and normalizes TAR ownership fields.
The guarantee is byte identity for the same selected bytes, configuration, TreeSift version, and compression implementation. Cross-version compressor identity is not promised without evidence.
- Keep rule evaluation independent from writers.
- Add explicit sibling APIs rather than dynamic backend discovery.
- Preserve ordering, trust boundaries, and atomic failure behavior.
- Add dependencies only when the standard library cannot satisfy an actual requirement.
- Optimize only against the benchmark harness and preserve behavior tests.
Context planning is a downstream consumer of SelectionPlan; it never reimplements
ignore precedence. Context mode composes a non-overridable AI-safety decision layer
with the existing matcher so dependency, cache, VCS, environment, and generated-output
paths can be pruned during traversal. Optional Git export-ignore filtering follows
selection, and positive --include patterns narrow the remaining regular files. Text
classification, sensitive-content checks, measurements, and SHA-256 are then recorded
in a full snapshot. changed-only and delta modes decide which snapshot entries are
rendered without discarding the full snapshot state used by future deltas.
Context rendering re-reads and hashes each file immediately before serialization. If the digest differs from the planned snapshot, generation aborts instead of producing a manifest that describes different bytes. Split outputs never split an individual source file.
Provider profiles are static data, not adapters or plugins. The project still avoids a dynamic provider framework because TreeSift does not authenticate with or upload to AI providers.