{title}
{description}
From e05d6a7f6caad1c31515a09bf6ce37f831a2b717 Mon Sep 17 00:00:00 2001
From: raiseCatError <315733358+raiseCatError@users.noreply.github.com>
Date: Sun, 18 Oct 2026 07:39:02 +0530
Subject: [PATCH] Website: retire the Learn page and correct stale pinned
references
Remove /learn/, its navigation entry, homepage and roadmap promotion, the
learn-concept media slot and sitemap/llms.txt entries. Add an audited editorial
correction overlay for release-pinned references and use it for the Context
Modules release status and the private project link in CONTRIBUTING. Fix both
canonical documents for future releases.
---
CONTRIBUTING.md | 2 +-
docs/architecture/context-modules.md | 4 +--
website/DESIGN.md | 6 ++--
website/LAUNCH.md | 4 +--
website/README.md | 22 +++++++++----
website/REVIEW.md | 4 +--
website/scripts/editorial.mjs | 33 +++++++++++++++++++
website/scripts/sync-upstream.mjs | 9 ++---
website/scripts/validate-content.mjs | 4 +++
website/src/components/Media.astro | 4 +--
website/src/content.config.ts | 2 +-
website/src/content/guides/commands.md | 2 --
website/src/content/guides/setup.md | 3 +-
.../src/content/reference/context-modules.md | 5 +--
website/src/content/reference/contributing.md | 3 +-
website/src/data/media.json | 3 +-
website/src/data/upstream.json | 10 ++++--
website/src/layouts/Base.astro | 6 ++--
website/src/layouts/Docs.astro | 5 +--
website/src/pages/docs/index.astro | 2 +-
website/src/pages/index.astro | 2 +-
website/src/pages/learn.astro | 13 --------
website/src/pages/llms.txt.ts | 2 +-
website/src/pages/roadmap.astro | 2 +-
website/src/pages/sitemap.xml.ts | 2 +-
website/src/styles/global.css | 6 ----
website/tests/browser/site.spec.mjs | 23 +++++++++----
website/tests/editorial.test.mjs | 23 +++++++++++++
28 files changed, 135 insertions(+), 71 deletions(-)
create mode 100644 website/scripts/editorial.mjs
delete mode 100644 website/src/pages/learn.astro
create mode 100644 website/tests/editorial.test.mjs
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 85cada01..14e2edcd 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -22,7 +22,7 @@ Before starting work, check:
- **[GitHub Issues](https://github.com/raiseCatError/notMyShell/issues)** — concrete actionable work; acceptance criteria in each issue are authoritative
- **[v0.20.0 Release](https://github.com/raiseCatError/notMyShell/releases/tag/v0.20.0)** — current stable release, merged through [PR #392](https://github.com/raiseCatError/notMyShell/pull/392) (see [ROADMAP.md](ROADMAP.md))
- **[CHANGELOG.md](CHANGELOG.md)** — the authoritative record of notable changes; see [Changelog](#changelog) below
-- **GitHub Project** — [NMSh Development](https://github.com/users/raiseCatError/projects/1) — live development status board
+- **GitHub Issues** — [raiseCatError/notMyShell issues](https://github.com/raiseCatError/notMyShell/issues) — public bug reports, proposals and development status
## Branch Model
diff --git a/docs/architecture/context-modules.md b/docs/architecture/context-modules.md
index 6153e8dc..ba48a067 100644
--- a/docs/architecture/context-modules.md
+++ b/docs/architecture/context-modules.md
@@ -8,8 +8,8 @@ without taking over shell execution or running anything the workspace chose.
> **Release status.** v0.17.0 shipped the foundation: typed fact metadata,
> native module routing and the Context Rail. Everything else described here —
> capability scheduling, the first-party module catalog, declarative Context
-> Packs, Status Strip routing and Status Strip 2.0, `/modules` and Claude Code agent context — is in
-> the v0.18 development stack, pending acceptance and release.
+> Packs, Status Strip routing and Status Strip 2.0, `/modules` and Claude Code agent context — shipped
+> in v0.18.0 and is part of every later release, including the current v0.20.0.
## From capability to presentation
diff --git a/website/DESIGN.md b/website/DESIGN.md
index a794b7cb..93f76aca 100644
--- a/website/DESIGN.md
+++ b/website/DESIGN.md
@@ -49,8 +49,7 @@ silently promoted by a build. A check-only sync reports drift without changing f
## Information architecture
-Product `/`, Features `/features/`, Install `/install/`, Docs `/docs/`, future Learn
-`/learn/`, Roadmap `/roadmap/`, Releases `/releases/`, Architecture `/architecture/`.
+Product `/`, Features `/features/`, Install `/install/`, Docs `/docs/`, Roadmap `/roadmap/`, Releases `/releases/`, Architecture `/architecture/`.
Docs progress from first run, concepts and everyday use through composer, completion,
transcript, sessions, prompts, themes, integrations, context, shells, configuration,
accessibility, troubleshooting, advanced usage, development and reference.
@@ -70,8 +69,7 @@ decorative animation. Original brand artwork is reused unmodified.
Marketing sections use editorial splits, numbered explanations and comparison rows,
not endless cards. A fine ruled media field with an abstract registration mark,
purpose label and honest pending notice reserves its real aspect ratio. No fake
-commands, output, playback buttons or product UI. Learn is a conceptual introduction,
-not a functional lesson player. The homepage stays static. Motion is limited to quick
+commands, output, playback buttons or product UI. The homepage stays static. Motion is limited to quick
article-only fades between documentation pages, short native dialog entry/exit and
hover feedback. No scroll-triggered reveals or JavaScript-gated content. Reduced
motion disables it. Focus rings and text labels carry state
diff --git a/website/LAUNCH.md b/website/LAUNCH.md
index 0cdff701..b0f60f83 100644
--- a/website/LAUNCH.md
+++ b/website/LAUNCH.md
@@ -57,7 +57,7 @@ followed by a successful rerun. None establishes final released-tag physical acc
| Prompts, Theme Studio, Chroma and Theme Bridge | Integrated; prompt/theme ownership contracts | Prompts, themes, configuration, accessibility |
| Rerunnable Setup | Integrated; `src/setup/SetupCat.ts`, `tests/setupOrder.test.ts` | Setup guide; starting points versus full guided wizard |
| Reactive Horizon first run | Integrated into production app paths at public `15d776ee`; `tests/startupApp.test.ts`, `tests/startupEnding.test.ts` | Setup guide; four choices, reactive sky, transparency, real-composer ending and bounded host offer |
-| Learn Mode | **Future proposal**, issue #398; not part of v0.20 code | Dedicated planned Learn page; isolation gates preserved |
+| Learn Mode | Deferred idea, issue #398; not part of v0.20 code | Intentionally not advertised; `/learn/` returns 404 |
## Onboarding integration boundary
@@ -105,7 +105,7 @@ reason to call the already integrated Horizon experience a future proposal.
- Curated guides and pages were reconciled against the release: welcome on every first
run, Keep Existing provider choices, the Tools tiers and flow, the update notice,
queue settings and history, platform evidence. Candidate-only wording is state-gated
- or removed. Learn Mode stays a planned proposal.
+ or removed. Learn Mode is not advertised.
- Checks on the synced tree: `npm test`, `npm run check`, `npm run build:launch`
(62 pages, internal links/anchors, sitemap, metadata, search), `npm run test:browser`
(17/17, axe in both themes and reduced motion). External links: 198 of 199 return
diff --git a/website/README.md b/website/README.md
index 3c21a4ba..16686fe3 100644
--- a/website/README.md
+++ b/website/README.md
@@ -22,7 +22,7 @@ website/
data/ Launch baseline, public releases, source hashes, media inventory
layouts/ Shared product shell and documentation layout
lib/ Shared release metadata and docs navigation
- pages/ Product, install, Learn, roadmap, docs and release routes
+ pages/ Product, install, roadmap, docs and release routes
scripts/ Small browser enhancement: theme, copy and search
styles/ Shared tokens, responsive layouts and prose styles
public/ Genuine brand artwork, robots and Cloudflare headers
@@ -161,9 +161,10 @@ not leave a half-fetched refresh. Filesystem write failures still require checki
the Git diff and rerunning the refresh; normal builds validate the complete result.
The roadmap is a curated editorial view linked to public issues, not an API dump.
-Recheck issue state and product direction during each release review. Issue #398 is
-authoritative for Learn Mode; it remains a future proposal with no date or version
-commitment. Never add an install command, fake course player or unsafe host-shell demo.
+Recheck issue state and product direction during each release review. The site does
+not advertise Learn Mode or any Bash/zsh course: issue #398 is a deferred, unscheduled
+idea about explaining NMSh's own interface and stays off the public site. Never add an
+install command, fake course player or unsafe host-shell demo.
Add product pages in `src/pages/`, reuse `Base`, `Code` and `Media`, and update sitemap
routes/global navigation deliberately. New or renamed docs paths need explicit
@@ -185,7 +186,6 @@ caption and future alt-text requirements. Every slot is currently intentionally
| `session-resume` | Detach and reattach a live shell | 1440×900 / 8:5 |
| `context-modules` | Native prompt, Rail and Status Strip | 1440×900 / 8:5 |
| `vespyr-appearance` | Vespyr and appearance choices | 1440×900 / 8:5 |
-| `learn-concept` | Future approved guide/practice concept | 1440×960 / 3:2 |
When genuine supplied assets are available, put them in `public/media/` and add
`src: "/media/name.webp"`, `kind: "image"`, and a specific `alt` to the corresponding
@@ -197,7 +197,7 @@ No video library, automatic playback or animation bypass is introduced. Match th
reserved ratio (the home slot is height-capped on desktop) to avoid layout movement.
Update the caption honestly when replacing pending media. Do not call a conceptual
-Learn image a working interface. Requirements in `altRequirement` are instructions
+image a working interface. Requirements in `altRequirement` are instructions
for a future author, never fabricated alt text for an unavailable asset. Build
validation rejects missing local assets, missing alt text, bad dimensions and
unapproved external media URLs. Genuine existing logo/lockup assets are copied
@@ -379,3 +379,13 @@ References: [disabled Git builds](https://developers.cloudflare.com/pages/config
theme switching usable without falsely claiming persistence.
- **Cloudflare root install builds the CLI:** set Root directory to `website` and
verify the explicit build command and dependency-install environment above.
+
+## Editorial corrections to pinned references
+
+Reference pages are synchronized from the tagged release and are never edited by hand
+(`validate-content` rejects it). A stale or wrong passage in a tagged document is
+corrected in `scripts/editorial.mjs` instead: each entry is pinned to one source commit,
+must match exactly once, is applied during `npm run sync:upstream`, is listed in the
+provenance manifest and appears on the page as an "Editorial update". Fix the canonical
+document on the development branch too, then delete the entry once a tagged release
+contains the fix.
diff --git a/website/REVIEW.md b/website/REVIEW.md
index d6686174..47643729 100644
--- a/website/REVIEW.md
+++ b/website/REVIEW.md
@@ -87,7 +87,7 @@ not the revised v0.20 baseline. They are retained as historical verification evi
## Shipped for review
-Home, Features, Install, documentation index, planned Learn, Roadmap, Releases,
+Home, Features, Install, documentation index, Roadmap, Releases,
historical release-note pages, Architecture and custom 404. The handbook includes
18 curated guides and 15 version-pinned technical references, with desktop sidebar,
compact navigation/contents, anchor links, previous/next and local full-text search.
@@ -120,7 +120,7 @@ Chrome covers 1440px desktop, 834px tablet and 390px mobile; dark and light them
blocked storage writes; clipboard success/denial; search results, no-results and
failed-index fallback; Escape focus return; no-JS docs; compact contents/permalinks;
404 and pending-media behavior. Automated axe checks exercise representative product,
-installation, learning and technical-doc pages in both themes.
+installation and technical-doc pages in both themes.
Rendered **webpage-only** viewport QA was visually inspected at desktop/tablet/mobile
sizes, using disposable external scratch. These images contain the website and its
diff --git a/website/scripts/editorial.mjs b/website/scripts/editorial.mjs
new file mode 100644
index 00000000..2da29cb6
--- /dev/null
+++ b/website/scripts/editorial.mjs
@@ -0,0 +1,33 @@
+// Audited corrections to release-pinned references. The tagged source is immutable, so a wrong or
+// stale sentence in it is corrected here, shown on the page as an editorial update and recorded in
+// the provenance manifest. Each correction applies only to the commit it was written against and
+// must match exactly once; remove it once the corrected text ships in a tagged release.
+export const corrections = [
+ {
+ id: 'context-modules-release-status',
+ commit: '65e4de55b2d8f1ad3a734a9d415a353b56b81e2c',
+ slug: 'context-modules',
+ note: 'The release-status paragraph said the module platform was still pending acceptance. It shipped in v0.18.0 and is part of v0.20.0.',
+ from: 'Packs, Status Strip routing and Status Strip 2.0, `/modules` and Claude Code agent context — is in\n> the v0.18 development stack, pending acceptance and release.',
+ to: 'Packs, Status Strip routing and Status Strip 2.0, `/modules` and Claude Code agent context — shipped\n> in v0.18.0 and is part of every later release, including the current v0.20.0.',
+ },
+ {
+ id: 'contributing-public-link',
+ commit: '65e4de55b2d8f1ad3a734a9d415a353b56b81e2c',
+ slug: 'contributing',
+ note: 'The tagged document linked to a private GitHub Project. The link now points to the public issue tracker.',
+ from: '- **GitHub Project** — [NMSh Development](https://github.com/users/raiseCatError/projects/1) — live development status board',
+ to: '- **GitHub Issues** — [raiseCatError/notMyShell issues](https://github.com/raiseCatError/notMyShell/issues) — public bug reports, proposals and development status',
+ },
+];
+
+export function applyEditorial(slug, commit, body) {
+ const applied = [];
+ let text = body;
+ for (const correction of corrections.filter(item => item.slug === slug && item.commit === commit)) {
+ if (text.split(correction.from).length !== 2) throw new Error(`Editorial correction ${correction.id} no longer matches exactly once; review or remove it.`);
+ text = text.replace(correction.from, () => correction.to);
+ applied.push(correction);
+ }
+ return { body: text, applied };
+}
diff --git a/website/scripts/sync-upstream.mjs b/website/scripts/sync-upstream.mjs
index 744e4eb3..e964b071 100644
--- a/website/scripts/sync-upstream.mjs
+++ b/website/scripts/sync-upstream.mjs
@@ -3,6 +3,7 @@ import { createHash } from 'node:crypto';
import { selectStable, normalizeMarkdown, renderReleaseMarkdown, assertReleaseCache, planOwnedRemovals } from './content.mjs';
import { sources } from './upstream-sources.mjs';
import { assertLaunch } from './launch.mjs';
+import { applyEditorial } from './editorial.mjs';
const repository = 'raiseCatError/notMyShell';
const root = new URL('../', import.meta.url);
@@ -53,9 +54,9 @@ const sha256 = text => createHash('sha256').update(text).digest('hex');
const files = [];
for (const source of sources) {
const original = await fetchText(`https://raw.githubusercontent.com/${repository}/${commit.sha}/${source.path}`);
- const body = normalizeMarkdown(original.replace(/^# .+\r?\n/, ''));
- const markdown = `---\ntitle: ${JSON.stringify(source.title)}\ndescription: ${JSON.stringify(`Canonical ${source.title.toLowerCase()} from the v${version} ${state} source.`)}\ngroup: Technical reference\norder: ${sources.indexOf(source) + 100}\nsource: ${JSON.stringify(source.path)}\n---\n${body}`;
- files.push({ source, original, markdown });
+ const { body, applied } = applyEditorial(source.slug, commit.sha, normalizeMarkdown(original.replace(/^# .+\r?\n/, '')));
+ const markdown = `---\ntitle: ${JSON.stringify(source.title)}\ndescription: ${JSON.stringify(`Canonical ${source.title.toLowerCase()} from the v${version} ${state} source.`)}\ngroup: Technical reference\norder: ${sources.indexOf(source) + 100}\nsource: ${JSON.stringify(source.path)}\n${applied.length ? `editorial: ${JSON.stringify(applied.map(item => item.note))}\n` : ''}---\n${body}`;
+ files.push({ source, original, markdown, editorial: applied.map(item => item.id) });
}
const history = releases.filter(release => !release.draft && !release.prerelease && /^v\d+\.\d+\.\d+$/.test(release.tag_name));
const releaseFiles = history.map(release => ({ name: `${release.tag_name}.md`, markdown: renderReleaseMarkdown(release) }));
@@ -98,7 +99,7 @@ const snapshot = {
const manifest = {
commit: commit.sha, version, state,
routes: Object.fromEntries(sources.map(source => [source.path, source.slug])),
- files: files.map(file => ({ ...file.source, sourceSha256: sha256(file.original), generatedSha256: sha256(file.markdown) })),
+ files: files.map(file => ({ ...file.source, sourceSha256: sha256(file.original), generatedSha256: sha256(file.markdown), ...(file.editorial.length ? { editorial: file.editorial } : {}) })),
};
await writeFile(new URL('src/data/release.json', root), JSON.stringify(snapshot, null, 2) + '\n');
await writeFile(new URL('src/data/launch.json', root), JSON.stringify(launch, null, 2) + '\n');
diff --git a/website/scripts/validate-content.mjs b/website/scripts/validate-content.mjs
index 39c4b759..c8142477 100644
--- a/website/scripts/validate-content.mjs
+++ b/website/scripts/validate-content.mjs
@@ -2,6 +2,7 @@ import { readFile, access, readdir } from 'node:fs/promises';
import { createHash } from 'node:crypto';
import { validateMedia, assertFileMembership } from './content.mjs';
import { assertLaunch } from './launch.mjs';
+import { corrections } from './editorial.mjs';
const root = new URL('../', import.meta.url);
const read = async path => JSON.parse(await readFile(new URL(path, root), 'utf8'));
@@ -16,6 +17,9 @@ for (const file of manifest.files) {
const markdown = await readFile(new URL(`src/content/reference/${file.slug}.md`, root));
const hash = createHash('sha256').update(markdown).digest('hex');
if (hash !== file.generatedSha256) throw new Error(`Generated reference changed: ${file.slug}. Edit upstream, not the snapshot.`);
+ const expected = corrections.filter(item => item.slug === file.slug && item.commit === manifest.commit).map(item => item.id);
+ if (JSON.stringify(expected) !== JSON.stringify(file.editorial || [])) throw new Error(`Editorial corrections for ${file.slug} do not match the provenance manifest. Run the upstream sync.`);
+ for (const item of corrections.filter(item => expected.includes(item.id))) if (!markdown.toString().includes(item.to) || markdown.toString().includes(item.from)) throw new Error(`Editorial correction ${item.id} is not applied exactly.`);
}
for (const item of release.history) {
const markdown = await readFile(new URL(`src/content/releases/${item.tag}.md`, root));
diff --git a/website/src/components/Media.astro b/website/src/components/Media.astro
index 1b203c40..bc9468cf 100644
--- a/website/src/components/Media.astro
+++ b/website/src/components/Media.astro
@@ -16,8 +16,8 @@ if (!slot) throw new Error(`Unknown media slot: ${id}`);
) : slot.src ? (
) : (
-
{description}
Route native modules where they make sense. Choose your palette and prompt provider. Keep Vespyr and motion, or choose a quieter view. The frontend adapts; the shell stays the shell.
Project, runtime, Git and system facts come from bounded local capabilities. Opening a repository is not permission to execute its code.
Context Engine →Theme Studio shapes NMSh. Opt-in Theme Bridge can carry that palette to supported tools through reviewed, managed files.
Themes and Chroma →Homebrew handles installation on macOS. Source builds support macOS, Linux beta and WSL 2, with Node.js 22+.
{release.tapVersion !== `v${launch.version}` &&The tap currently provides {release.tapVersion}. The installation guide includes a pinned source build of this {launchLabel}.
}Requirements and installation →A future guide-and-practice experience for Bash and zsh. Real understanding, with isolation that must be proven before real-shell practice is offered.
Read a lesson, try it, then work out why it behaved that way. A proposed place to learn Bash and zsh through practice, with skills you can use in any ordinary terminal.
NMSh already keeps input, output and context together. Learn Mode would use that space to teach Bash and zsh themselves, rather than a collection of NMSh shortcuts.
On wide terminals, a lesson guide could sit beside a practice area. Smaller terminals would use adaptive tabs or a toggle, keeping both reading and practice usable.
Short explanations, clear objectives, layered hints and a searchable course-like reading experience.
Practice with files, pipes, quoting and scripts. Feedback should explain the actual result, not reward memorizing one exact command.
Versioned checkpoints, unfinished practice files and resumable learning, designed to stay local.
The initial teaching shells proposed are Bash and zsh. Their differences must be taught honestly; Fish is deferred. No course, command or practice terminal is available from this page.
Terminals and shells. Paths and directories. Files, permissions and how to ask for help.
Proposed foundationsStreams and pipes. Quoting, variables, exit status and inspecting mistakes instead of guessing.
Proposed practiceWrite and edit small shell scripts, debug them, and apply the concepts in practical challenges.
Proposed scriptingA temporary folder is not a secure sandbox. A real shell can reach other files, credentials, processes and the network. Isolation has to be enforced outside the lesson.
Real Bash or zsh practice would require proven OS-enforced containment, a bounded practice filesystem, no host home or credential mounts, no network by default, resource limits and reliable cleanup.
If strong isolation cannot be verified on a platform, the proposal requires a clearly labeled simulator or disabled execution. It must never silently fall back to your ordinary host shell. Simulation must not claim full Bash/zsh compatibility.
Dangerous demonstrations remain simulated. A command blacklist or confirmation prompt is educational feedback, not the security boundary.
A clear view of the product, the work being finished and the ideas that still need testing.
The {launchLabel} release brings the existing frontend together with the terminal workflow, a reviewed first run, background tasks and expanded context. Release notes and history →
A persistent composer and shell, live sessions, serial queue, execution timeline, output selection, Copy Actions, reviewed reports and comparisons.
Execution workflows →Session-owned background tasks, managed Claude Code beta, worktree tools, read-only GitHub inspection and a larger native module catalog. The experimental workspace sidebar remains Off by default.
Tools and workspaces →Shipping a feature and proving it on every host are separate steps. Automated tests are not physical acceptance.
The Reactive Horizon starting point, guided Setup and the shared Tools flow shipped in v0.20.0 and were physically accepted on macOS.
Setup and first run →Item-by-item checklist passes in Ghostty and Terminal.app, and any physical Linux, Omarchy or WSL 2 pass, are still open. Linux remains beta on automated CI.
Physical QA record →Directions worth investigating, not scheduled commitments. Scope, feasibility, security and design approval can change what eventually ships.
Guided Bash/zsh lessons, practice files, helpful feedback and resumable progress. Strong real-shell isolation must be verified, or execution must be explicitly simulated or disabled.
Explore future Learn Mode →Additional managed-agent adapters, workflow tool integrations and stronger isolation for executable mods require independent capability and security evidence.
Directions worth investigating, not scheduled commitments. Scope, feasibility, security and design approval can change what eventually ships.
Additional managed-agent adapters, workflow tool integrations and stronger isolation for executable mods require independent capability and security evidence.
Reviewed {launch.verifiedAt}. See the source roadmap and public issues for the full context. An open issue is not automatically a product commitment.