Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,15 @@ jobs:
# somebody touched a `; doc:` block (or src/ structure) without
# re-running `make manifest`. Engine-free — only needs python3
# and git, both already installed above.
#
# `check-manifest` wraps `manifest-check` and additionally
# asserts dist/repo.meta.json is tracked and committed (Phase 0
# tier-1 contract — the org catalog generator fetches that file
# by raw URL and a missing/stale copy would break the smoke
# test in m-dev-tools/.github).
run: |
export PATH="/tmp/venv/bin:$PATH"
make manifest-check
make check-manifest

- name: AI skill drift check
# Regenerates dist/skill/{SKILL.md,manifest-index.md,patterns.md,
Expand Down
182 changes: 182 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
---
# Machine-readable project descriptor.
name: m-stdlib
kind: [m-library, library]
status: active
languages: [mumps]

runtime:
needs:
- "yottadb (primary target)"
optional:
- "iris (portability target where reasonable)"
excludes:
- "gtm (deliberately out of scope)"

distribution:
pypi: null
github: m-dev-tools/m-stdlib

location: ~/projects/m-stdlib

exposes:
m_routines: "see docs/modules/index.md"
formats_produced: []

consumes:
formats: []
services: []

companions:
- project: m-cli
relation: "m-stdlib has architectural priority over m-cli — m-cli should consume m-stdlib utilities, not duplicate them"
- project: m-standard
relation: "m-stdlib obeys m-standard's reconciled language definitions; rules apply via m-cli lint"
- project: tree-sitter-m
relation: "syntax must parse cleanly under tree-sitter-m"
- project: m-test-engine
relation: "default Docker engine for `make test` and CI"

incompatibilities:
- "GT.M not supported. AGPL-3.0 YottaDB and IRIS only."
- "Ships pure-M source; no compiled artifacts. Caller links the routines via $ZRO."

docs:
primary: README.md
# Every doc that records change is in docs/tracking/.
tracking_root: docs/tracking/
changelog: docs/tracking/changelog.md
module_tracker: docs/tracking/module-tracker.md # canonical "what's done / in flight / proposed" view
discoverability_tracker: docs/tracking/discoverability-tracker.md
parallel_tracks: docs/tracking/parallel-tracks.md # dispatch view across all parallel tracks
todo: docs/tracking/TODO.md # resume-here pointer
discoveries: docs/tracking/discoveries.md # discoveries register: in-project pivots + external toolchain findings (renamed from TOOLCHAIN-FINDINGS.md 2026-05-10)
tracking_readme: docs/tracking/README.md # the four-bucket doc model that everything under docs/tracking/ follows
implementation_plan: docs/plans/m-stdlib-implementation-plan.md
tdd_orchestration: docs/plans/tdd-orchestration-plan.md # m-stdlib ↔ m-cli joint milestones
---

# m-stdlib — Claude Project Context

Pure-M (and selectively `$ZF`-bound) runtime library filling the
highest-impact gaps in M's standard library. Sibling project to m-cli,
m-standard, and tree-sitter-m. YottaDB-first; IRIS-portable where
reasonable.

See [README.md](README.md) for the public-facing overview and
[`docs/guides/users-guide.md`](docs/guides/users-guide.md) for the
deep user reference.

## Tracking conventions

**All changes to m-stdlib — releases, in-flight work, deferred items,
external-toolchain findings, and discovered issues — are recorded in
[`docs/tracking/`](docs/tracking/).** The repo root carries no
change-tracking documents; CLAUDE.md / README.md are pointers only.

The canonical files inside `docs/tracking/`:

| File | Purpose |
|------|---------|
| [`README.md`](docs/tracking/README.md) | Defines the four-bucket doc model (planning · implementation · discoveries · tracking) that everything under docs/tracking/ follows. Read this first. |
| [`changelog.md`](docs/tracking/changelog.md) | Release history (Keep-a-Changelog format). One entry per tag. |
| [`module-tracker.md`](docs/tracking/module-tracker.md) | Master per-module tracker — Summary table (Done checkbox + module rows) + closed-tickets archaeology (T1–T30) + Must-know section. Per-module deep history lives in [`docs/modules/<m>.md` § History](docs/modules/); proposals (was Table 2) live in [`docs/plans/future-modules-plan.md`](docs/plans/future-modules-plan.md). |
| [`discoverability-tracker.md`](docs/tracking/discoverability-tracker.md) | Wave A–D implementation tracker for the discoverability & tooling plan; tabular summary + per-task narrative with progress logs. |
| [`parallel-tracks.md`](docs/tracking/parallel-tracks.md) | Dispatch view across L1–L27 / H1–H3 / m-cli companion C-tracks. |
| [`discoveries.md`](docs/tracking/discoveries.md) | Discoveries register — every issue that wasn't anticipated in a locked plan but had to be addressed during implementation. Both internal m-stdlib pivots and external findings against m-cli / tree-sitter-m / YDB / vista-meta. (Renamed from TOOLCHAIN-FINDINGS.md 2026-05-10; scope broadened.) |
| [`TODO.md`](docs/tracking/TODO.md) | "Resume here" pointer; thin index over the trackers. |

**Process rule.** Any commit that touches a module's source, tests,
or per-module doc MUST update the relevant row(s) in the appropriate
tracker in the same commit (the rule defined in
[`module-tracker.md`](docs/tracking/module-tracker.md)). Commits that
ship a tagged release MUST add a corresponding entry to
[`changelog.md`](docs/tracking/changelog.md).

Plans (forward-looking specs that get locked before implementation
starts) live in [`docs/plans/`](docs/plans/), separate from tracking.

## Architectural rule

**m-stdlib has priority over m-cli.** When both projects need a utility,
implement it here first; m-cli imports.

## Setup

m-stdlib ships pure-M source; there is no compiled artifact to install.
The toolchain dependencies are `m-cli` (Python) and the YottaDB runtime.

```bash
# Clone m-cli alongside m-stdlib and install it into a venv.
git clone https://github.com/m-dev-tools/tree-sitter-m ~/projects/tree-sitter-m
git clone https://github.com/m-dev-tools/m-cli ~/projects/m-cli
cd ~/projects/m-cli
python3 -m venv .venv
.venv/bin/pip install -e ".[lsp]" ../tree-sitter-m

# Engine: start m-test-engine for `make test` / `make coverage`.
make -C ~/projects/m-test-engine up # provides DockerEngine for m-cli
```

The `M` Makefile variable defaults to `$HOME/projects/m-cli/.venv/bin/m`;
override it if your checkout lives elsewhere.

## Test

```bash
make test # engine-bound; needs YDB transport (LocalEngine, DockerEngine, or SSHEngine)
make safe-test # same suites with auto-recovery from vista-meta failure modes
make coverage # gated at 85% per module
make check # fmt-check + lint + test (fast dev loop)
make ci # check + TAP + JSON coverage (CI-shaped invocation)
```

Engine-free checks (`fmt-check`, `lint`, `manifest-check`,
`skill-check`, `doctest-check`) work on a fresh clone without YDB
configured.

## Build / generate

The repo commits its own generated artefacts under `dist/` — every
change to `src/STD*.m` or to a `; doc:` block must be followed by a
regenerate-and-commit, gated by CI.

```bash
make manifest # → dist/stdlib-manifest.json + dist/errors.json
make skill # → dist/skill/{SKILL.md,manifest-index.md,patterns.md,error-codes.md}
make doctest # → tests/STD<MOD>DOCTST.m for every module with Pattern-A @examples
make frontmatter # re-syncs YAML frontmatter on docs/modules/std*.md
```

The Phase 0 `repo.meta.json` (`dist/repo.meta.json`) is hand-edited —
not regenerated — and is covered by `make check-manifest` (see below).

## Verify

These commands match `dist/repo.meta.json`'s `verification_commands`
and are what an agent should run to confirm a change in this repo:

```bash
make manifest # regenerate dist/
make test # run the suite
make check-manifest # drift gate: dist/ matches src/ AND repo.meta.json is committed
```

## Guardrails

- **Do not hand-edit `dist/stdlib-manifest.json`, `dist/errors.json`,
`dist/skill/`, or `tests/STD*DOCTST.m`.** They are regenerated from
`src/STD*.m` doc-comments by `make manifest`, `make skill`, and
`make doctest`. CI's drift gates will reject any direct edit.
- **`dist/repo.meta.json` is the one file under `dist/` that is
hand-edited.** Bump `verified_on` to today's date whenever you
touch it; `make check-manifest` asserts that `dist/` (including
`repo.meta.json`) is committed and clean.
- **Do not introduce GT.M support.** AGPL-3.0 YottaDB and IRIS only —
GT.M is deliberately out of scope.
- **Do not duplicate utilities into m-cli.** m-stdlib has architectural
priority; m-cli consumes from here.
- **Trackers update in the same commit.** Any commit that touches a
module's source, tests, or per-module doc must update the relevant
row in `docs/tracking/module-tracker.md` (see "Tracking conventions"
above).
102 changes: 0 additions & 102 deletions CLAUDE.md

This file was deleted.

1 change: 1 addition & 0 deletions CLAUDE.md
21 changes: 18 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@

SHELL := /bin/bash

# m-cli venv — Python entry point for `m fmt` / `m lint` / `m test` / `m coverage`.
M ?= $(HOME)/projects/m-cli/.venv/bin/m
# m-cli — Python entry point for `m fmt` / `m lint` / `m test` / `m coverage`.
# Resolved from $PATH by default. Maintainers who keep an unactivated
# m-cli venv can override per-shell or per-invocation, e.g.
# make fmt-check M=$HOME/projects/m-cli/.venv/bin/m
M ?= m

# m-test-engine — local checkout for `make engine-up` / `engine-down`.
# Override if you cloned it elsewhere.
M_TEST_ENGINE ?= $(HOME)/projects/m-test-engine

.PHONY: all fmt fmt-check lint test safe-test coverage check ci clean print-env seed unseed manifest manifest-check frontmatter skill skill-check skill-install doctest doctest-check doctest-run engine-up engine-down engine-status
.PHONY: all fmt fmt-check lint test safe-test coverage check ci clean print-env seed unseed manifest manifest-check check-manifest frontmatter skill skill-check skill-install doctest doctest-check doctest-run engine-up engine-down engine-status

# vista-meta connection contract — silently included if present.
# Preserves the maintainer's existing workflow but no longer hard-errors
Expand Down Expand Up @@ -132,6 +135,18 @@ manifest-check: manifest
|| { echo "ERROR: dist/errors.json out of date — run 'make manifest' and commit."; exit 1; }
@echo "manifest: clean"

# `check-manifest` is the Phase 0 tier-1 drift gate. It composes the
# existing manifest-check (generated payloads) with an assertion that
# the hand-edited dist/repo.meta.json is tracked and clean. The org
# catalog generator fetches dist/repo.meta.json by raw URL — a missing
# or stale file would break Phase 0's smoke test in .github.
check-manifest: manifest-check
@git ls-files --error-unmatch dist/repo.meta.json >/dev/null 2>&1 \
|| { echo "ERROR: dist/repo.meta.json is not tracked — 'git add dist/repo.meta.json' and commit."; exit 1; }
@git diff --exit-code -- dist/repo.meta.json \
|| { echo "ERROR: dist/repo.meta.json has uncommitted changes — review and commit."; exit 1; }
@echo "check-manifest: clean"

# `make frontmatter` re-syncs YAML frontmatter on every docs/modules/std*.md
# from the manifest + index.md (WA6). Idempotent — files that already carry
# frontmatter are skipped. Use `--force` to overwrite (e.g. after WA2 backfill
Expand Down
16 changes: 16 additions & 0 deletions dist/repo.meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://raw.githubusercontent.com/m-dev-tools/.github/main/profile/repo.meta.schema.json",
"id": "tool:m-stdlib",
"repo": "https://github.com/m-dev-tools/m-stdlib",
"role": "Pure-M runtime standard library — STD* modules",
"language": ["m"],
"license": "AGPL-3.0",
"agent_instructions": "AGENTS.md",
"verified_on": "2026-05-10",
"exposes": {
"modules": "dist/stdlib-manifest.json",
"errors": "dist/errors.json"
},
"consumes": ["tool:m-test-engine"],
"verification_commands": ["make manifest", "make test", "make check-manifest"]
}
15 changes: 12 additions & 3 deletions tools/gen-manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,14 +402,23 @@ def build_label_entry(


def read_stdlib_version() -> str:
"""Read the most-recent versioned entry from CHANGELOG.md.
"""Read the most-recent versioned entry from the changelog.

Skips an `[Unreleased]` heading if present so the manifest's
stdlib_version stays anchored to the last shipped tag while
work accumulates against the next one.

The changelog moved in commit 90e694e from `CHANGELOG.md` at the
repo root to `docs/tracking/changelog.md` (per the four-bucket
tracking-doc model). Look at the new path first, fall back to the
old one for back-compat with checkouts predating that commit.
"""
changelog = REPO_ROOT / "CHANGELOG.md"
if not changelog.exists():
candidates = (
REPO_ROOT / "docs" / "tracking" / "changelog.md",
REPO_ROOT / "CHANGELOG.md",
)
changelog = next((p for p in candidates if p.exists()), None)
if changelog is None:
return ""
for line in changelog.read_text(encoding="utf-8").splitlines():
m = re.match(r"^##\s*\[([^\]]+)\]", line)
Expand Down
Loading