Metadata-Version: 2.4
Name: gromtools
Version: 0.4.0
Summary: Lowest-order layer of the Grom system: atomic, single-purpose Python primitives.
Author-email: Carson <shapeslines@users.noreply.github.com>
License-Expression: LicenseRef-Proprietary
Project-URL: Repository, https://github.com/shapeslines/GromTools
Project-URL: Changelog, https://github.com/shapeslines/GromTools/blob/main/CHANGELOG.md
Keywords: grom,primitives,automation,uuidv7,smtp
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: ruff<0.17,>=0.16.1; extra == "dev"
Requires-Dist: coverage>=7; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Dynamic: license-file

> **FLEET STATUS · ALIVE** (2026-08-17) — lowest-order atomic Python primitives. Authority: [FLEET-MAP](https://github.com/shapeslines/GromCodebase/blob/main/docs/fleet/FLEET-MAP.md) · decision: vault 2026-08-17 provenance ratification.

# GromTools

> **Lowest-order layer of the Grom system.** A library of small, atomic,
> single-purpose Python calls (primitives), plus a **Meta-tools testing lane**
> (`meta/`) for vault OIP tools under dual-home development.

GromTools is the foundation the rest of the Grom stack is built on. Higher
layers compose these primitives — GromTools itself never reaches "up" the stack
and avoids long-running orchestration.

**Mail / SMTP:** atomic `gromtools.mail` only (no env, no templates, no retries).
The fleet **compose / carriage** layer is **[GromPort](https://github.com/shapeslines/GromPort)**
(`SmtpChannel`, event planner, outbox). Archived GromSync / GromScheduler are
not the current composers.

## Design contract (Python primitives)

A GromTools primitive should be:

- **Atomic** — one call, one job. No multi-step workflows.
- **Pure-ish** — deterministic given its inputs where possible; side effects are
  explicit and narrow (e.g. "write this file", not "sync everything").
- **Dependency-light** — a primitive should be cheap to import and call.
- **Composable** — designed to be chained by a higher layer, not to orchestrate.

```python
from gromtools import (
    __version__,
    token_hex,
    token_urlsafe,
    build_message,
    message_recipients,
    message_as_bytes,
    parse_message,
    smtp_send,
)
```

One-page contract reference for every primitive (signatures, raises,
examples): [docs/primitives.md](docs/primitives.md).

Domain modules today include `tokens` (secure random tokens + constant-time
`token_compare`), `mail`
(pure MIME assembly/parse helpers, and explicit SMTP send with optional
envelope overrides; credentials are call args, never env reads; use
`smtp_send(..., dry_run=True)` to validate without opening a socket),
`fs` (`ensure_within` path fence + fenced atomic `safe_write` + `path_inside`
trailing-sep-safe containment predicate), `fence`
(reusable `Fence` root bundling fenced read/write/JSONL appends + `paths_overlap`/
`fence_overlaps` cross-owner disjointness check), `filelock`
(cross-platform stdlib exclusive file lock — `FileLock` timeout/poll,
`FileLockTimeout`; msvcrt win32 / fcntl POSIX; resolves the GromPort +
GromRuntime hand-rolled drift), `claims` (declared cross-session path
claims — `write_claim`/`read_claims`/`release_claim`/`audit_claims` over a
claims dir, deadline-only staleness, plain-JSON on-disk contract for the
GromAgentKit `fence-gate.mjs` hook; composes `fence.paths_overlap`), `text`
(`normalize_newlines`, `slugify`, `project_slug_for_cwd`, `preview` middle-truncate,
`truncate` end-truncate-with-suffix, `estimate_tokens` ceil(len/4) heuristic), `uuidv7` (RFC 9562
mint/validate), `digest` (`sha256_hex` + fenced `file_sha256` + `sample_gate`
deterministic sampling — the house
pin/verify contract), `iso` (ISO-8601 parse/format + UTC `iso_now` / `iso_today`),
`frontmatter` (strict stdlib YAML-subset parse/serialize for vault notes),
`jsonl` (line-delimited JSON read + fenced atomic append), `dedup`
(`canonical_json` + versioned `dedup_key` fingerprints + `tuple_key` field
idempotency), `dag` (pure DAG
algorithms — `topological_order`/`depth_by_node`/`levels`/`ancestor_map`/
`bernstein_pairs`; extracted from the Grommash/GromRuntime twin-port),
`manifest`
(provenance-manifest build/verify), `chain` (hash-linked append records),
`telemetry` (comm-telemetry record kernels — Node-parity mirror of the vault
`hashRow`/`canonicalRow`, pinned vectors in CI; G1 usage-chain + econ-field
vocabulary `USAGE_EVENTS`/`SURFACES`/`USAGE_STATES` + `validate_econ_fields`), `funnel` (The Funnel
command-line grammar — Node-parity mirror, pinned vectors in CI), `aisort`
(AI-export sorter classification: model detection, `Project - Topic
(Model).ext` parsing, naming/metadata kernels from SPEC-AI-EXPORT-SORTER),
`vaultpath` (dual-home path resolution — Python mirror of
`meta/lib/shim-resolve.mjs`: `OIP_VAULT`/`GROMBRAIN_VAULT` vault root,
`GROMTOOLS_ROOT`â†’package-rootâ†’vault-probe GromTools root, pinned contract
in CI), `markdown` (GFM table render + `\|`-cell escape — the atom
gen-board/eval-run/conformance-review hand-rolled), `wikilink` (Obsidian
link parse/render/scan — canonical atom for two divergent vault regexes),
`backoff` (pure exponential delay schedule + jitter — the retry atom the
GromPort outbox composes), `agentstatus` (fleet session-declaration records —
strict schema, fenced atomic writer, deterministic fleet view for the vault
`90 Meta/agent-status` surface), `worktree` (git worktree orchestration —
list/add/remove thin wrapper, zero-authority like `smtp_send`), `ledger`
(raw-line hash-chained JSONL — the coordination-ledger format: `prev` =
sha256 of the previous raw line, JSON.stringify-compact, BOM-tolerant
verify), `semver` (strict SemVer 2.0.0 parse/compare/bump for the
semver'd release posture), `gitrepo` (read-only git state — branch/sha/
dirty + oneline log parse, zero-authority sibling of `worktree`), `retry`
(call-with-backoff retry composing `backoff`), `templating` (strict
`{{var}}` substitution — the vault `tpl-*` convention atom), `redact`
(recursive dict/list redaction `redact_record` + house secret-shape
detection `detect_secret_signatures` / `redact_secrets` for telemetry-row
shapes), `seq` (`diff_first_divergence` — first-divergence diff on
ordered sequences, Grommash journal authority),
and `salvage` (+ `session_salvage` CLI:
session-transcript recovery —
`discover` / `triage` / `write_spec`, outputs fenced to the invocation cwd).

## Layout

```
gromtools/        # Python primitives (tokens, mail, fs, fence, filelock, text, uuidv7, digest, iso, frontmatter, jsonl, dedup, dag, manifest, chain, telemetry, funnel, redact, aisort, vaultpath, markdown, wikilink, backoff, agentstatus, worktree, ledger, semver, seq, salvage, …)
meta/             # Meta-tools testing lane (Node; Waves 1–6: validators + stateless kernels)
tests/            # pytest modules
pyproject.toml
```

> **Supporting work — Mermaid projection (VM-GTL-001).** Package layout and
> ecosystem layer cake. Source: this Layout section and the ecosystem table
> below. Callers compose Port; Port composes Tools atoms — Tools never reaches
> up.

```mermaid
flowchart TB
  Callers["Higher callers"] --> Port["GromPort carriage"]
  Port --> Tools["gromtools/ primitives"]
  MetaSrc["meta/ testing source"] -. dual-home .-> VaultShim["vault 90 Meta/tools shims"]
  subgraph repo ["GromTools repo"]
    Tools
    MetaSrc
    Tests["tests/"]
  end
```

## Meta-tools test / production split

| Lane | Path | Role |
|---|---|---|
| Testing / source | `meta/*.mjs` | Tool bodies, `--selftest`, `npm test` |
| Production / live | vault `90 Meta/tools/*.mjs` | Skills keep calling vault paths (shims) |

Wave 1–4 dual-home tools: `gen-uuid`, `uuidv7-check`, `codex-index-gap`,
`owner-gated-action-validate`, `conformance-review`, `patch-templates-s13`,
`prompt-contract-validate`, `dispatch-economics-validate`, `vault-lint`,
`validate-arc-package`, `validate-conquest-gates`, `validate-literature-provenance`,
`verify-uuid`.  
See [meta/README.md](meta/README.md). Set `GROMTOOLS_ROOT` if the clone is not a
sibling under `Desktop/GITHUB/GromTools`.

```bash
cd meta && npm test
```

## Validation

| Check | Command | CI |
|---|---|---|
| Python unit tests | `python -m pytest` | 3.10 / 3.11 / 3.13 |
| Python lint | `ruff check .` | 3.10 / 3.11 / 3.13 |
| Meta-tool selftests | `cd meta && npm test` | node 20 |

All three must pass before a PR lands (`.github/workflows/ci.yml`). The meta
suite covers every dual-home tool body (`--selftest`), the shim-resolution
unit, and an end-to-end vault-shim install simulation.

On Windows, the symlink-fence security tests (`tests/test_fs.py`,
`tests/test_session_salvage_security.py`) skip without Developer Mode or
admin symlink privilege; they run fully in CI (Linux).

## Session salvage CLI

```bash
python -m gromtools.session_salvage discover [--since ISO] [--cwd PATH] [--errors-only] [--limit N] [--json]
python -m gromtools.session_salvage triage <since-iso>
python -m gromtools.session_salvage spec <transcript.jsonl> <out.md>
```

Recovers stuck/API-errored Claude Code sessions from their on-disk JSONL
transcripts into resume specs. Deterministic — verbatim user input is copied
exactly, never paraphrased. Writers are fenced to the invocation cwd:
`triage.json` always lands in cwd and `spec` refuses an `out` that resolves
outside cwd.

## Place in the Grom ecosystem

| Layer    | Repo              | Responsibility                                                                 |
|----------|-------------------|--------------------------------------------------------------------------------|
| Carriage | **GromPort**      | Transport compose: SMTP/Slack channels, dispatch *timing*, delivery results.   |
| Policy   | **Grommash**      | Should this run, in what order? (scheduling policy — not Port).                |
| Runtime  | **GromRuntime**   | Allowed? Receipt? Ingress adapters (e.g. Slack export).                        |
| Lowest   | **GromTools** â—€   | Atomic Python primitives + Meta-tool source during testing.                    |
| Special  | **GromViz**       | RETIRED 2026-08-14. Carbon/PDF now lives in `Shapeslines-Web/vendor/gromviz`.  |
| Face     | **GromDash**      | Dashboard rewrite — should call GromPort for mail, not reinvent smtplib.       |

Call direction (mail): `caller â†’ GromPort â†’ gromtools.mail`.  
GromSync / GromScheduler are **archived migration sources**; see GromPort charter.

## Status

**Live.** Python primitives ship (`tokens`, `mail`, `fs`, `fence`, `filelock`, `text`,
`uuidv7`, `digest`, `iso`, `frontmatter`, `jsonl`, `dedup`, `dag`, `manifest`,
`chain`, `telemetry`, `funnel`, `redact`, `aisort`, `vaultpath`, `markdown`,
`wikilink`, `backoff`, `agentstatus`, `worktree`, `ledger`, `semver`,
`gitrepo`, `retry`, `templating`, `seq`, `salvage` + `session_salvage` CLI). Meta
Waves 1–6 live under `meta/` — validators (Waves 1–4, with vault production
shims) plus stateless kernels: Wave 5 funnel/telemetry/redact, and 12 Wave-6
consolidation kernels (`frontmatter`, `path`, `argv`, `walk-md`,
`is-main-entry`, `seat-chain`, `econ-telemetry`, `glossary`, `tel-adapters`,
`validate`, `model`, `walk-json`) + Tier-C fold-ins (`diff`, `query`) + B5-secondary
kernels (`world-context`, `telemetry-grade`, `chain-ledger`) — Wave 6 is consolidation, not dual-home,
and has no vault shims yet.
No-authority charter ratified 2026-08-01 (F12 â†’ b):
stateless, semver'd, consumed. **1184 tests, ≥95% per-module coverage
(CI-gated; 99% total measured 2026-08-12), 7 cross-language
parity corpora** (uuidv7/telemetry/funnel/redact/mojibake/vaultpath/
ledger-row). CI
restored 2026-08-06 (owner fixed billing; the Linux leg caught + fixed
pre-existing Windows-path test assumptions; per-module â‰¥95% coverage is now
an enforced CI gate; `workflow_dispatch` available for re-runs). ADR-0018
absorption into GromRuntime does **not** forbid this dual-home for Meta-tool
source.
