@hobocode/thought-layer 0.7.0 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,7 @@ import {
9
9
  aggregateConfidence, statusFromConfidence, gradeFromConfidence,
10
10
  checkDomains, registrarSearchUrl,
11
11
  computeProjection, fmtMoney,
12
- applyStateOp, runScaffold, runDeploy, runSync,
12
+ applyStateOp, runScaffold, runDeploy, runSync, runArtifacts, runWiki,
13
13
  type Assumptions, type StateOp,
14
14
  } from "../core/index.ts";
15
15
 
@@ -160,7 +160,7 @@ export default function (pi: ExtensionAPI) {
160
160
  path: Type.Optional(Type.String({ description: "Project dir or .json path; selects WHICH state file to use. Defaults to ./.thought-layer/state.json. Use a named file (e.g. .thought-layer/acme.json) to keep ideas separate; for 'list', a project dir to scan." })),
161
161
  qId: Type.Optional(Type.String({ description: "Question id (for 'answer'/'feedback'). Must be a real Thought Layer question id." })),
162
162
  value: Type.Optional(Type.Unknown({ description: "For 'answer': the answer string. For 'artifact': the artifact object." })),
163
- artifact: Type.Optional(Type.String({ description: "For 'artifact': one of bizModel, grill, assets, research, swot, prd, naming, brand." })),
163
+ artifact: Type.Optional(Type.String({ description: "For 'artifact': one of bizModel, grill, assets, research, swot, prd, naming, brand, governance." })),
164
164
  mode: Type.Optional(Type.String({ description: "For 'feedback': 'panel' (3 personas) or a single persona key." })),
165
165
  personas: Type.Optional(Type.Array(PersonaSchema, { description: "For 'feedback': one entry per persona with its assessment + confidence." })),
166
166
  endState: Type.Optional(Type.String({ description: "For 'feedback': 'open' (still iterating), 'pass' (cleared 0.85), or 'setAside' (frozen with to-dos)." })),
@@ -268,4 +268,64 @@ export default function (pi: ExtensionAPI) {
268
268
  return text(r.message, r.details);
269
269
  },
270
270
  });
271
+
272
+ // tl_artifacts: generate the full deliverable bundle from a session (PRD,
273
+ // requirements, glossary, build prompt, brand guide + look book + logo, SWOT
274
+ // and business-model infographics, market research, a landing page) plus any
275
+ // on-disk build/deploy provenance, and deliver it to the user's OWN private
276
+ // sessions repo under artifacts/<session>/ via the sync git plumbing.
277
+ pi.registerTool({
278
+ name: "tl_artifacts",
279
+ label: "Thought Layer: deliver artifacts",
280
+ description:
281
+ "Generate the full asset bundle for a session and deliver it to your OWN private sessions repo (the one tl_sync set up), under artifacts/<session>/. " +
282
+ "Builds, from the saved state: PRD.md, Requirements.md, DomainGlossary.md, BuildPrompt.md, the brand style guide + LookBook.html + Logo.svg, SWOT.svg and BusinessModel.svg infographics, MarketResearch.md, and a deployable landing page; it also copies any on-disk build/deploy provenance (build.json, deploy.json, BACKEND/TRACEABILITY/DECISIONS.md, schema.sql, netlify.toml) into a Deploy/ folder, and writes an artifacts.json manifest the wiki reads. " +
283
+ "Force-adds past the sessions .gitignore, commits, and pushes (newest delivery wins; artifacts are not field-merged). Pass name to pick the session; noDeliver writes locally without committing. Needs a sessions workspace (tl_sync init) first.",
284
+ parameters: Type.Object({
285
+ name: Type.Optional(Type.String({ description: "Session name whose artifacts to deliver (defaults to the workspace's active session)." })),
286
+ workspace: Type.Optional(Type.String({ description: "Select an existing sessions workspace by label." })),
287
+ path: Type.Optional(Type.String({ description: "Explicit source state file to read (defaults to the session file in the clone)." })),
288
+ dir: Type.Optional(Type.String({ description: "Explicit clone dir for the workspace (overrides the configured one)." })),
289
+ message: Type.Optional(Type.String({ description: "Commit message for the delivery." })),
290
+ noPush: Type.Optional(Type.Boolean({ description: "Commit locally without pushing." })),
291
+ noDeliver: Type.Optional(Type.Boolean({ description: "Write the bundle into the clone but do not commit or push." })),
292
+ domain: Type.Optional(Type.String({ description: "Real domain for the landing page (canonical/OG)." })),
293
+ founder: Type.Optional(Type.String({ description: "Founder name for the landing page." })),
294
+ }),
295
+ async execute(_id, params): Promise<ToolResult> {
296
+ const p = params as { name?: string; workspace?: string; path?: string; dir?: string; message?: string; noPush?: boolean; noDeliver?: boolean; domain?: string; founder?: string };
297
+ const r = runArtifacts(
298
+ { name: p.name, workspace: p.workspace, path: p.path, dir: p.dir, message: p.message, noPush: p.noPush, noDeliver: p.noDeliver, domain: p.domain, founderName: p.founder },
299
+ { generatedAt: new Date().toISOString() },
300
+ );
301
+ return text(r.message, r.details);
302
+ },
303
+ });
304
+
305
+ // tl_wiki: build/refresh a PRIVATE Notion wiki (an internal intranet) from the
306
+ // session + the delivered artifacts. Notion is private by default, so the docs
307
+ // are behind the user's own auth. BYOK: the token is read from the environment
308
+ // only; the parent page (shared with the integration) is passed as an id/url.
309
+ pi.registerTool({
310
+ name: "tl_wiki",
311
+ label: "Thought Layer: Notion wiki",
312
+ description:
313
+ "Build or refresh a PRIVATE Notion wiki (an internal intranet) for a session: a root page, one child page per workflow area (Big Idea, Business Model, Brand, Market Research, Strategy, PRD, Decision Science), rendered natively in Notion, plus an Artifacts database that links the files delivered by tl_artifacts. " +
314
+ "Notion pages are private to the user's workspace, so this satisfies an auth requirement with no public exposure. BYOK: the integration token is read ONLY from THOUGHT_LAYER_NOTION_TOKEN (or NOTION_TOKEN) in the environment, never a parameter. Setup once: create an internal integration at notion.so/my-integrations, set the token, share a page with the integration, and pass that page as parentPage. " +
315
+ "Idempotent: it stores the page ids locally and refreshes content on re-run; replace recreates the wiki from scratch; dryRun reports the plan with no network call. Run tl_artifacts first so the Artifacts database has GitHub links.",
316
+ parameters: Type.Object({
317
+ name: Type.Optional(Type.String({ description: "Session name to publish (defaults to the workspace's active session)." })),
318
+ parentPage: Type.Optional(Type.String({ description: "Notion page id or URL the integration is shared with (where the wiki root is created). Or set THOUGHT_LAYER_NOTION_PARENT." })),
319
+ workspace: Type.Optional(Type.String({ description: "Select an existing sessions workspace by label." })),
320
+ path: Type.Optional(Type.String({ description: "Explicit source state file (defaults to the session file in the clone)." })),
321
+ dir: Type.Optional(Type.String({ description: "Explicit clone dir for the workspace." })),
322
+ replace: Type.Optional(Type.Boolean({ description: "Recreate the wiki from scratch (new pages) instead of refreshing the existing one." })),
323
+ dryRun: Type.Optional(Type.Boolean({ description: "Build the plan and report area/block/artifact counts with no network call." })),
324
+ }),
325
+ async execute(_id, params): Promise<ToolResult> {
326
+ const p = params as { name?: string; parentPage?: string; workspace?: string; path?: string; dir?: string; replace?: boolean; dryRun?: boolean };
327
+ const r = await runWiki({ name: p.name, parentPage: p.parentPage, workspace: p.workspace, path: p.path, dir: p.dir, replace: p.replace, dryRun: p.dryRun });
328
+ return text(r.message, r.details);
329
+ },
330
+ });
271
331
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hobocode/thought-layer",
3
- "version": "0.7.0",
3
+ "version": "0.8.5",
4
4
  "description": "The Thought Layer: rigor for building. Validate an idea, grill it into a buildable spec, then build and deploy it, inside the agent you already use. BYOK, no telemetry.",
5
5
  "license": "MIT",
6
6
  "author": "Hobocode LLC <jerm@hobocode.net>",
@@ -71,6 +71,10 @@
71
71
  "core/backend-io.ts",
72
72
  "core/scaffold.ts",
73
73
  "core/scaffold-io.ts",
74
+ "core/artifacts.ts",
75
+ "core/artifacts-io.ts",
76
+ "core/notion.ts",
77
+ "core/notion-io.ts",
74
78
  "core/deploy.ts",
75
79
  "core/deploy-io.ts",
76
80
  "dist",
@@ -0,0 +1,7 @@
1
+ Deliver the full asset bundle for this idea to my own private sessions repo.
2
+
3
+ Use the `tl_artifacts` tool (or `tl artifacts` via `npx -y @hobocode/thought-layer`). It reads my saved session from the sessions repo, so honor `--name <session>` / `--workspace` / `--dir`; I must have a sessions workspace set up first (`tl sync init`).
4
+
5
+ Build, from the saved state: the PRD, requirements, domain glossary, the paste-ready build prompt, the brand style guide + look book + logo, the SWOT and business-model infographics, the market research brief, and a deployable landing page. Also copy any on-disk build/deploy provenance (build.json, deploy.json, BACKEND/TRACEABILITY/DECISIONS.md, schema.sql, netlify.toml) into a Deploy/ folder, and write an artifacts.json manifest. Force-add past the sessions .gitignore, commit, and push (newest delivery wins; artifacts are not field-merged).
6
+
7
+ Tell me how many files were delivered, the path (`artifacts/<session>/`), and the GitHub link. Then I can run `/tl-wiki` to organize them into a private Notion intranet.
@@ -0,0 +1,7 @@
1
+ Apply the **thought-layer-compliance** skill. Research the governance, regulatory, compliance, licensing, and taxation-prep needs for my new business and hand me a cited report to review with my own legal and tax advisors. This is research, not legal or tax advice; say so up front.
2
+
3
+ First read my saved state (`tl read`) for what the business is and who it serves, then ask only what is missing, in one short batch: my jurisdiction (country + state/province, and city if local permits apply), entity type (LLC, C-corp, sole proprietor, etc., or undecided), sector, whether I have contractors/employees, revenue status, and where my customers are.
4
+
5
+ Then run deep web research (use your web tools) on my exact jurisdiction + entity + sector across five tracks: governance and entity formation; regulatory and licenses/permits (with costs and renewal cycles); taxation (filing deadlines and forms); employment and contractor compliance (only if I hire); and data privacy and consumer protection (only if relevant). For every requirement, give me a live link, the issuing authority, the trigger, the cost, and the deadline. Prefer official government/registry sources and confirm the links resolve.
6
+
7
+ Give me a structured report: the disclaimer, a snapshot of my inputs, a section per applicable track, a critical path to launch, the top risks, and which advisor to engage first with the questions to ask them. Then save it as the `governance` artifact (`tl artifact governance --data '...'`) so it flows into `tl artifacts` (Compliance.md) and the Notion wiki, and tell me that path.
@@ -0,0 +1,9 @@
1
+ Apply the **thought-layer-wiki** skill. Build me a private Notion wiki, an internal intranet that organizes everything this workflow produced.
2
+
3
+ First make sure I have delivered the artifacts (`tl artifacts --name <session>`), so the wiki can link to the files in my repo; if I have not, build from the session state and tell me the Artifacts database will be empty until I deliver them. The wiki reads my session from my private sessions repo, so honor `--name` / `--workspace` / `--dir`.
4
+
5
+ Read my Notion token only from the environment (`THOUGHT_LAYER_NOTION_TOKEN` or `NOTION_TOKEN`), never ask me to paste it. I create an internal integration at notion.so/my-integrations, set the token, and share a Notion page with the integration; pass that page as `--parent-page <id or url>`. If the token or the parent page is missing, tell me exactly what to do rather than pretending it worked.
6
+
7
+ Dry-run first (`tl wiki --name <session> --dry-run`) so I can see the area pages, block counts, and artifact count. Then build it: a root "<Product> workspace" page, a child page per workflow area that has content (Big Idea, Business Model, Brand, Market Research, Strategy, PRD, Decision Science), rendered natively in Notion, plus an Artifacts database that links each delivered file to its GitHub copy. Upload small files only where no link exists; Notion's free tier caps uploads at 5 MiB, so larger files link out.
8
+
9
+ It is idempotent: re-running refreshes the existing pages (the page ids are stored locally, never synced); `--replace` rebuilds from scratch. After it is built, give me the root page URL.
@@ -0,0 +1,139 @@
1
+ ---
2
+ name: thought-layer-compliance
3
+ description: "Research a founder's governance, regulatory, compliance, licensing, and taxation-prep needs for a new business and hand back a cited report to review with their OWN legal and tax advisors. A research-and-deliver skill, not an adversarial panel: it asks a few simple questions (jurisdiction, entity type, sector, employees, revenue, where customers are), asking only what prior answers do not already cover, then runs deep web research with the host agent's web tools across governance/formation, regulatory and licenses/permits, taxation, employment/contractor, and data-privacy/consumer-protection. Every requirement carries a live link, authority, trigger, cost, and deadline. The output is a Markdown report (a critical path to launch, top risks, advisor-engagement order), fronted by a clear disclaimer that it is research and a starting checklist, NOT legal or tax advice. Run it once the business is defined; it persists as the governance artifact so it flows into tl artifacts (Compliance.md) and the Notion wiki."
4
+ ---
5
+
6
+ # Compliance, licensing & tax readiness (research, not advice)
7
+
8
+ You are a compliance and regulatory researcher. Your job is to surface, source, and
9
+ **link** the governance, licensing, tax, employment, and privacy requirements a founder
10
+ will face in their exact jurisdiction, entity type, and sector, so they walk into their
11
+ lawyer's and accountant's office already knowing the landscape and the questions to ask.
12
+
13
+ You do not give legal or tax advice, and you never imply you can. You gather authoritative
14
+ sources, name requirements plainly, and point to live links. The founder's licensed
15
+ advisors decide what applies and what to do. Honesty over reassurance: if a requirement is
16
+ uncertain, say so and link the source rather than guessing.
17
+
18
+ **This is a research-and-deliver skill, not one of the kit's adversarial deep-dives.**
19
+ There is no panel, no confidence score, no 0.85 gate. A few intake questions, then deep
20
+ research, then a cited report.
21
+
22
+ ## The disclaimer (state it up front, every time)
23
+
24
+ Open the report (and your first message) with, in substance:
25
+
26
+ > This is research and a starting checklist, **not legal or tax advice.** Requirements
27
+ > change and turn on specifics this report cannot fully capture. Verify everything with a
28
+ > lawyer and an accountant licensed in your jurisdiction before acting. This is a snapshot
29
+ > dated <today's date>; links were checked at generation time.
30
+
31
+ ## When to run it
32
+
33
+ Run this once the business is **defined** (you know what it does and roughly where it
34
+ operates), as a launch-readiness pass. It is not part of the mandatory backbone. If you
35
+ are handed a one-line idea with no shape, say so and route the founder to the
36
+ thought-layer-framework backbone first; do not research compliance for a business that
37
+ does not yet exist.
38
+
39
+ ## Step 1: Intake (a few simple questions)
40
+
41
+ First read the shared state for context (the `tl_state read` tool, or `tl read`): pull the
42
+ business description from `what-statement` and the customer type from `target-market` if
43
+ they are present, so you do not re-ask what is already known. Then ask **only what is
44
+ missing**, in one short batch:
45
+
46
+ 1. **Jurisdiction.** Country, and state/province (and city, if local permits plausibly
47
+ apply, e.g. food, retail, in-home services).
48
+ 2. **Entity type.** LLC, C-corp, S-corp, sole proprietor, partnership, nonprofit, B-corp,
49
+ other, or "undecided" (if undecided, research the realistic options for this sector and
50
+ note the trade-offs, but flag that the choice is the founder's and their advisor's).
51
+ 3. **Sector / industry.** What the business actually does (e.g. B2B SaaS, e-commerce,
52
+ consulting, food service, fintech, healthcare). This drives sector-specific licensing
53
+ and privacy.
54
+ 4. **People.** None yet, contractors, or employees (roughly how many).
55
+ 5. **Revenue.** Pre-revenue, or live (rough scale), since tax and sales-tax obligations
56
+ scale with revenue and headcount.
57
+ 6. **Where customers are.** The regions/countries of customers and users (drives sales-tax
58
+ or VAT nexus and data-privacy law).
59
+
60
+ Keep it light. If the founder does not know an answer (e.g. entity type), proceed with the
61
+ realistic default for the sector and mark it as an assumption to confirm with an advisor.
62
+
63
+ ## Step 2: Deep research (with links)
64
+
65
+ Use your web research tools (WebSearch / WebFetch, or a deep-research skill/harness if one
66
+ is available) to research the founder's exact **jurisdiction + entity + sector**
67
+ combination across the five tracks below. The kit ships no web tooling; you do the
68
+ research with the tools your host gives you. Prefer **primary, authoritative sources**
69
+ (government agencies, official registries, tax authorities, the relevant regulator) and
70
+ date what you find.
71
+
72
+ For **every requirement** you surface, capture:
73
+ - the **requirement** in plain language,
74
+ - the **issuing authority** (agency, statute, or official registry),
75
+ - a **live link** (open it to confirm it resolves; do not cite a dead or guessed URL),
76
+ - the **trigger** (when it applies: at formation, at a revenue threshold, on first hire, etc.),
77
+ - the **cost** (one-time and/or annual, with the source, when available),
78
+ - the **deadline or renewal cycle** (date or interval), when applicable.
79
+
80
+ The five tracks:
81
+
82
+ 1. **Governance & formation.** How to register the entity (the office and the steps), a
83
+ registered agent if required, the operating agreement or bylaws expected, and the tax
84
+ id (EIN / business number) and how to get it.
85
+ 2. **Regulatory & licenses/permits.** Federal, state/provincial, and local licenses and
86
+ permits, plus any sector-specific ones (e.g. food, alcohol, financial services, health,
87
+ childcare, transport). Costs, renewal cycles, and realistic approval timelines.
88
+ 3. **Taxation prep.** The taxes this entity owes (income, payroll, sales tax / VAT,
89
+ franchise/privilege, excise where relevant), the registrations needed, the filing
90
+ deadlines and form numbers (or links to the forms), what triggers each, and when a CPA
91
+ is genuinely needed.
92
+ 4. **Employment & contractor compliance** (only if they have or plan contractors or
93
+ employees). Worker classification and the misclassification risk in this jurisdiction,
94
+ payroll and withholding, mandatory benefits/insurance (e.g. workers' comp,
95
+ unemployment), and the core labor-law obligations.
96
+ 5. **Data privacy & consumer protection** (only if they handle customer data or sell to
97
+ consumers). Applicable privacy law given where customers are (e.g. GDPR, CCPA/CPRA),
98
+ sector privacy (e.g. HIPAA for health data), payment handling (PCI DSS), and consumer
99
+ rules (terms, refunds/cancellation, truth-in-advertising).
100
+
101
+ If a track does not apply (no employees, no consumer data), say so in one line rather than
102
+ padding it.
103
+
104
+ ## Step 3: The report
105
+
106
+ Produce one structured Markdown report:
107
+
108
+ 1. **The disclaimer** (above), first.
109
+ 2. **Snapshot** of the inputs: jurisdiction, entity type, sector, people, revenue,
110
+ customer regions, and the date.
111
+ 3. **A section per applicable track** (governance, licenses, taxation, employment,
112
+ privacy), each a short list of requirements with their link, authority, trigger, cost,
113
+ and deadline.
114
+ 4. **Critical path to launch**: the few registrations/licenses that block launch and the
115
+ order to do them, with rough timelines.
116
+ 5. **Top risks**: the three or so highest-stakes items (a kill-switch regulation, a
117
+ catastrophic penalty, personal-liability exposure if the entity or classification is
118
+ wrong).
119
+ 6. **Bring this to your advisors**: which advisor to engage first (usually a CPA for tax
120
+ structure, employment counsel before the first hire, general counsel for data/consumer
121
+ exposure) and the specific questions to ask each, with the links attached.
122
+
123
+ Every claim links to a source. No source, no claim.
124
+
125
+ ## Step 4: Persist
126
+
127
+ Store the report so it travels with the idea and flows into the founder's deliverables:
128
+
129
+ - Save it with the state tool: `tl_state` op `artifact`, key **`governance`**, value
130
+ `{ jurisdiction, entityType, sector, employees, revenue, report: "<the full markdown>",
131
+ sources: ["<url>", ...], generatedAt: "<iso>" }` (or `tl artifact governance --data '...'`).
132
+ - Once saved, it is delivered as **`Compliance.md`** by `tl artifacts` and rendered as the
133
+ **Compliance & Tax** page (and listed in the Artifacts database) by `tl wiki`, alongside
134
+ the rest of the founder's workspace. Mention that path so they can deliver it.
135
+ - If neither `tl_state` nor the `tl` CLI is available, output the full report in chat and
136
+ tell the founder to save it.
137
+
138
+ Do not write the state JSON by hand; use the tool, which stores the artifact in the exact
139
+ shape the rest of the kit reads.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: thought-layer-wiki
3
+ description: "Auto-generate a PRIVATE Notion wiki: an internal intranet for the founder that organizes everything the workflow built, the validation thinking, brand and styles, business model, PRD, deploy rules, and links to every delivered artifact. Runs from the kit (no web app, no proxy) and calls the Notion API directly. Notion pages are private to the user's own workspace, so the docs sit behind their own auth, not public. BYOK: the integration token is read ONLY from THOUGHT_LAYER_NOTION_TOKEN (or NOTION_TOKEN) in the environment, never a parameter; the parent page shared with the integration is passed as an id or URL. Run tl artifacts first so the Artifacts database links the files in the user's repo. Prefers the tl_wiki tool or the tl wiki CLI; dry-run first. Idempotent: it stores page ids locally and refreshes on re-run, replace rebuilds from scratch. One child page per workflow area; small files upload, larger link to GitHub (free tier caps uploads at 5 MiB)."
4
+ ---
5
+
6
+ # Wiki it: a private internal intranet in Notion
7
+
8
+ The wiki is the founder's keepable home for everything the workflow produced: the thinking that created the business, the brand and styles, the business model, the PRD and requirements, the deploy rules, and a linked index of every delivered artifact. It runs from the kit on the user's own machine and writes into the user's own Notion. Notion pages are private by default, so this satisfies a "behind auth, not public" requirement with no extra infrastructure.
9
+
10
+ ## Preconditions
11
+
12
+ 1. **A sessions workspace.** The wiki reads the session from the user's private sessions repo (set up by the `tl_sync` tool / `tl sync init`). Honor the usual selection: `--name <session>` (or the workspace's active session), `--workspace <label>`, or an explicit `--dir`.
13
+ 2. **Delivered artifacts (recommended).** Run the `tl_artifacts` tool / **`tl artifacts`** first so `artifacts/<session>/artifacts.json` exists. The wiki reads it to fill the Artifacts database with GitHub links. Without it, the wiki still builds from the session state, but the Artifacts database is empty; the tool says so. Tell the user to deliver artifacts first for the full result.
14
+ 3. **A Notion integration (one-time, BYOK).** The user creates an internal integration at https://www.notion.so/my-integrations, copies the secret, and sets it as `THOUGHT_LAYER_NOTION_TOKEN` (or `NOTION_TOKEN`) in the environment. Then, in Notion, they open the page that should hold the wiki, click **Share**, and add the integration so it has access. That page's id or URL is the `parent-page`. The token is read **only from the environment**; never ask the user to paste it into the chat or put it in a parameter or file.
15
+
16
+ ## How to run it
17
+
18
+ Use the tool, never a hand-written Notion `curl`:
19
+ - **Pi:** the `tl_wiki` tool. Start with `tl_wiki { name, dryRun: true }` to show the plan (area pages, block counts, artifact count), then `tl_wiki { name, parentPage }` to build it.
20
+ - **Any shell agent (Claude Code, CI, a plain terminal):** `tl wiki --name <session> --dry-run`, then `tl wiki --name <session> --parent-page <id|url>` (via `npx -y @hobocode/thought-layer tl wiki`).
21
+
22
+ Always **dry-run first** and show the user the area + artifact plan, then build.
23
+
24
+ ## What it builds
25
+
26
+ - A root page **"<Product> workspace"** under the shared parent page.
27
+ - One **child page per workflow area** that has content: The Big Idea, Business Model, Brand, Market Research, Strategy, Product (PRD), Decision Science. Empty areas are skipped. Content is rendered **natively** as Notion blocks (the palette and parties become tables, the brand guide and PRD become headings/lists), so it reads well without relying on file previews.
28
+ - An **Artifacts database** that lists each delivered file with its category and a **link to its GitHub copy** (decks, look book, logo, infographics, the build prompt, the deploy provenance).
29
+
30
+ ## Files: link vs upload (the 5 MiB rule)
31
+
32
+ Notion's free tier caps a single uploaded file at 5 MiB. The wiki links artifacts to their GitHub copy when the artifacts were delivered (the normal path), and reserves direct upload for small files where no link exists. Notion cannot inline-render arbitrary SVG or HTML, so the logo, look book, and infographics are linked or attached, not embedded as broken previews; their data is also rendered natively where it makes sense (the palette table, the brand guide text).
33
+
34
+ ## Idempotency and re-runs
35
+
36
+ Notion has no upsert, so the tool stores the root page id, the per-area page ids, and the Artifacts database id in a **machine-local** `~/.thought-layer/notion.json` (keyed by session). A normal re-run **reuses those pages and refreshes their content**; `--replace` / `replace: true` rebuilds the wiki from scratch (new pages). This id map is local provenance, never synced into the sessions repo.
37
+
38
+ ## Honest failure
39
+
40
+ If the tool returns `ok: false`, relay its message verbatim, do not claim a wiki was built:
41
+ - **No token** -> tell the user to create the integration and set `THOUGHT_LAYER_NOTION_TOKEN`.
42
+ - **No parent page** -> tell them to share a Notion page with the integration and pass it as `--parent-page`.
43
+ - **Parent not shared** -> the integration cannot see the page; in Notion, Share the page with the integration, then re-run.