drafted 1.16.0 → 1.17.0
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.
- package/agent-instructions/global.md +1 -50
- package/install-mcp.sh +1 -50
- package/mcp/gates.mjs +5 -5
- package/mcp/server.mjs +921 -2663
- package/mcp/test-org-guards.mjs +22 -1
- package/mcp/widgets/canvas-overview.html +19 -3
- package/package.json +1 -1
- package/plugin/commands/create-project.md +7 -10
- package/plugin/commands/create-skill.md +3 -3
- package/plugin/commands/extract.md +2 -2
- package/plugin/commands/improve-project-harness.md +3 -3
- package/plugin/commands/improve-skill.md +2 -2
- package/plugin/commands/improve-wiki.md +3 -3
- package/plugin/commands/ingest.md +3 -3
- package/plugin/commands/onboard-drafted.md +2 -2
- package/plugin/skills/drafted/SKILL.md +35 -31
- package/src/shared/constants.mjs +1 -1
package/mcp/test-org-guards.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import assert from 'node:assert/strict';
|
|
|
5
5
|
import { mkdtempSync } from 'node:fs';
|
|
6
6
|
import { join } from 'node:path';
|
|
7
7
|
import { tmpdir } from 'node:os';
|
|
8
|
-
import { projectlessMutationNeedsOrg, boundOrgRejected, receiptOrg } from './server.mjs';
|
|
8
|
+
import { projectlessMutationNeedsOrg, boundOrgRejected, receiptOrg, splitOrgScope, stripUrlOrigin } from './server.mjs';
|
|
9
9
|
import { loadPersistedProject, savePersistedProject } from './active-project-store.mjs';
|
|
10
10
|
|
|
11
11
|
// One rule governs create AND fork (a fork is a create). A write proceeds when its
|
|
@@ -145,6 +145,27 @@ assert.equal(boundOrgRejected({ message: `not a member of org "${stale}"` }), fa
|
|
|
145
145
|
);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
// Shape A grammar: org is the top folder of the filesystem (/o/<org>/<root>/...).
|
|
149
|
+
// The org segment is stripped for the root handlers and carried as the per-request
|
|
150
|
+
// scope; bare roots stay accepted (backward compat, session working org).
|
|
151
|
+
assert.deepEqual(splitOrgScope('/o/acme/wiki/engineering/authz.md'), { path: '/wiki/engineering/authz.md', org: 'acme' }, 'org-scoped wiki path strips to the bare root + org');
|
|
152
|
+
assert.deepEqual(splitOrgScope('/o/acme/projects/design/beoflow/wireframes/x.html'), { path: '/projects/design/beoflow/wireframes/x.html', org: 'acme' }, 'org-scoped project path strips to the bare root + org');
|
|
153
|
+
assert.deepEqual(splitOrgScope('/o/acme'), { path: '/', org: 'acme' }, 'ls /o/<org> lists that org\'s roots');
|
|
154
|
+
assert.deepEqual(splitOrgScope('/o/acme/'), { path: '/', org: 'acme' }, 'trailing slash on the org root is harmless');
|
|
155
|
+
assert.deepEqual(splitOrgScope('/o/acme%20brand/skills'), { path: '/skills', org: 'acme brand' }, 'org segment is URL-decoded');
|
|
156
|
+
assert.deepEqual(splitOrgScope('/wiki/engineering'), { path: '/wiki/engineering', org: null }, 'bare root paths pass through untouched');
|
|
157
|
+
assert.deepEqual(splitOrgScope('/projects/x/y/z.html'), { path: '/projects/x/y/z.html', org: null }, 'bare project paths pass through untouched');
|
|
158
|
+
assert.ok(splitOrgScope('/o/').error, 'a bare /o/ is an invalid org-scoped path');
|
|
159
|
+
assert.ok(splitOrgScope('/o/').error?.includes('expected /o/<org>/<root>'), 'error names the expected grammar');
|
|
160
|
+
|
|
161
|
+
// Full share URLs (Q2): the URL's pathname IS the fs path — stripping the origin must
|
|
162
|
+
// leave an addressable path, and non-URL inputs pass through untouched.
|
|
163
|
+
assert.equal(stripUrlOrigin('https://drafted.live/o/acme/wiki/engineering/authz.md'), '/o/acme/wiki/engineering/authz.md', 'full URL strips to its pathname');
|
|
164
|
+
assert.equal(stripUrlOrigin('https://drafted.live/o/acme/projects/beoflow/designs/pricing/hero.html?x=1'), '/o/acme/projects/beoflow/designs/pricing/hero.html', 'URL query params are dropped with the origin');
|
|
165
|
+
assert.equal(stripUrlOrigin('/o/acme/wiki/x'), '/o/acme/wiki/x', 'plain paths pass through untouched');
|
|
166
|
+
assert.equal(stripUrlOrigin('not a url'), 'not a url', 'non-URL input passes through');
|
|
167
|
+
assert.equal(stripUrlOrigin('/f/00000000-0000-0000-0000-000000000000'), '/f/00000000-0000-0000-0000-000000000000', '/f/ frame links pass through');
|
|
168
|
+
|
|
148
169
|
console.log('org-guard policy OK');
|
|
149
170
|
// Importing server.mjs builds the stdio MCP singleton, which opens a WS reconnect
|
|
150
171
|
// loop that keeps the event loop alive. Assertions are done — exit deterministically.
|
|
@@ -128,11 +128,27 @@
|
|
|
128
128
|
return String(s).replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
// Derive the Drafted server origin from payload URLs (frameUrl, canvasUrl) so the
|
|
132
|
+
// widget deep-links correctly on local installs and hosted servers alike — never
|
|
133
|
+
// hardcode https://drafted.live (breaks localhost/self-hosted deployments).
|
|
134
|
+
function serverOrigin(sc) {
|
|
135
|
+
const candidates = [
|
|
136
|
+
sc.canvasUrl, sc.serverUrl,
|
|
137
|
+
...(Array.isArray(sc.projects) ? sc.projects.map(p => p.canvasUrl).filter(Boolean) : []),
|
|
138
|
+
...(Array.isArray(sc.projects) ? sc.projects.map(p => p.frameUrl).filter(Boolean) : []),
|
|
139
|
+
...(Array.isArray(sc.entries) ? sc.entries.map(e => e.frameUrl).filter(Boolean) : []),
|
|
140
|
+
];
|
|
141
|
+
for (const u of candidates) {
|
|
142
|
+
try { return new URL(u).origin; } catch { /* keep looking */ }
|
|
143
|
+
}
|
|
144
|
+
return 'https://drafted.live';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function renderProjects(projects, activeId, origin) {
|
|
132
148
|
if (!projects?.length) return '<div class="empty">No projects yet. Use project(action="create") to start one.</div>';
|
|
133
149
|
return projects.slice(0, 30).map(p => {
|
|
134
150
|
const isActive = p.id === activeId;
|
|
135
|
-
const url = p.slug ?
|
|
151
|
+
const url = p.slug ? `${origin}/project/${escapeHtml(p.slug)}` : '#';
|
|
136
152
|
return `
|
|
137
153
|
<a class="project" href="${url}" target="_blank" rel="noopener">
|
|
138
154
|
<div>
|
|
@@ -170,7 +186,7 @@
|
|
|
170
186
|
if (Array.isArray(sc.projects)) {
|
|
171
187
|
document.getElementById('title').textContent = `${sc.projects.length} project${sc.projects.length === 1 ? '' : 's'}`;
|
|
172
188
|
document.getElementById('subtitle').textContent = sc.activeProject ? 'One active' : 'None active — use project(action="open") to switch';
|
|
173
|
-
root.innerHTML = renderProjects(sc.projects, sc.activeProject);
|
|
189
|
+
root.innerHTML = renderProjects(sc.projects, sc.activeProject, serverOrigin(sc));
|
|
174
190
|
return;
|
|
175
191
|
}
|
|
176
192
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drafted",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.0",
|
|
4
4
|
"description": "Drafted — visual thinking surface for humans and AI agents. Renders HTML, markdown, images, and code as frames on a zoomable canvas, with MCP tools for AI agents and real-time sync for humans.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Start a new project — or a reusable template — with proper search of knowledge
|
|
2
|
+
description: Start a new project — or a reusable template — with proper search of knowledge and skills first
|
|
3
3
|
argument-hint: <project name and what you want to do>
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -8,16 +8,13 @@ Spin up a project on the surface, or generalize one into a reusable template. Go
|
|
|
8
8
|
First ask: **a new project, or a reusable template?** (This command does both.)
|
|
9
9
|
|
|
10
10
|
Search before creating (also satisfies the gates):
|
|
11
|
-
1. `wiki
|
|
12
|
-
2. `
|
|
13
|
-
3. `template(action="list")` for an existing template to fork. [G3 — also enforced on `project(action="create")`.]
|
|
11
|
+
1. `fs(search, path/o/<org>/wiki", query="<terms>")` for relevant knowledge. [G1]
|
|
12
|
+
2. `fs(search, path/o/<org>/skills", query="<topic>")` for procedures that should be attached. [G2/G3]
|
|
14
13
|
|
|
15
14
|
Then:
|
|
16
|
-
-
|
|
17
|
-
- `
|
|
18
|
-
-
|
|
19
|
-
- `
|
|
20
|
-
- Attach the relevant skills you found with `skill(action="attach")`.
|
|
21
|
-
- `focus` the brief so the user watches it land.
|
|
15
|
+
- Create the project — a project is a folder: `fs(mkdir, path/o/<org>/projects/<name>")`. It starts with **no layers**; you define them by writing into them.
|
|
16
|
+
- `fs(write, path/o/<org>/projects/<name>/<layer>/<lane>/brief.md", content=...)` a real brief at the earliest layer (goal, audience, constraints — 6-12 lines, not a placeholder). The layer + lane auto-create.
|
|
17
|
+
- Attach the relevant skills you found via the skill gates.
|
|
18
|
+
- `fs(ls, path/o/<org>/projects/<name>")` to confirm the structure, and hand the user the `projectUrl` from the response.
|
|
22
19
|
|
|
23
20
|
For a **template**: build the layer structure + anchored guidance, then note how to fork it next time. Don't speculatively fill downstream frames — wait for direction.
|
|
@@ -6,8 +6,8 @@ argument-hint: <what the procedure is for>
|
|
|
6
6
|
Turn a repeatable way of working into a Drafted skill so every future agent in the org follows it. Procedure: $ARGUMENTS
|
|
7
7
|
|
|
8
8
|
Do the searches first (they also satisfy the gates):
|
|
9
|
-
1. `wiki
|
|
10
|
-
2. `
|
|
9
|
+
1. `fs(search, path/o/<org>/wiki", query="<terms>")` for relevant org knowledge the procedure should reference. [G1]
|
|
10
|
+
2. `fs(search, path/o/<org>/skills", query="<topic>")` for prior art — an existing skill to improve instead of duplicating. [G2 — also enforced on writing a new skill.] If a close match exists, prefer `/drafted:improve-skill`.
|
|
11
11
|
|
|
12
12
|
Then define a PROPER procedure, not a vague note:
|
|
13
13
|
- a clear trigger ("when to use this"),
|
|
@@ -15,4 +15,4 @@ Then define a PROPER procedure, not a vague note:
|
|
|
15
15
|
- success criteria / what "done right" looks like,
|
|
16
16
|
- written in the second person so any agent can follow it directly. Keep it sharp (~40 lines).
|
|
17
17
|
|
|
18
|
-
Show the draft to the user with a proposed `name` (Title Case), one-line `description`, `tags` (3-5), and `triggerPatterns`. After approval, `
|
|
18
|
+
Show the draft to the user with a proposed `name` (Title Case), one-line `description`, `tags` (3-5), and `triggerPatterns`. After approval, write it with `fs(write, path/o/<org>/skills/<slug>", content=...)` — the slug is derived from the name. Confirm with the slug and note it will auto-surface on matching tasks.
|
|
@@ -7,9 +7,9 @@ Session-end deposit. Harvest what's durable from this conversation back into the
|
|
|
7
7
|
|
|
8
8
|
Review the session, then **present the user options for which store(s) to deposit into** — don't auto-decide. Offer any that apply:
|
|
9
9
|
|
|
10
|
-
- **Knowledge → wiki** — durable facts, decisions, or findings worth keeping. Search first (`
|
|
10
|
+
- **Knowledge → wiki** — durable facts, decisions, or findings worth keeping. Search first (`fs(search, path/o/<org>/wiki", ...)`) to avoid fragmenting, then `fs(write, path/o/<org>/wiki/<path>", ...)`.
|
|
11
11
|
- **Procedure → skill** — a repeatable way of working that emerged. Follow `/drafted:create-skill`.
|
|
12
|
-
- **Template → surface** — a reusable project structure that emerged. `
|
|
12
|
+
- **Template → surface** — a reusable project structure that emerged. Build it as a project via `fs(mkdir, ...)` + frames.
|
|
13
13
|
|
|
14
14
|
Show the user the candidate deposits per store, let them pick which to keep, then write the chosen ones with their approval. Confirm what landed where.
|
|
15
15
|
|
|
@@ -7,9 +7,9 @@ When the user had to correct the work in this project, codify the correction so
|
|
|
7
7
|
|
|
8
8
|
1. Identify the recurring correction(s) or standing rule from this session.
|
|
9
9
|
2. Choose the right Drafted-side gate per correction (each counts toward the project's context budget):
|
|
10
|
-
- **Project anchor** — a brief, constraint, or style guide that must be in context project-wide: `
|
|
11
|
-
- **Attached skill** — a procedure that must be loaded before work: `/drafted:create-skill` (or `
|
|
12
|
-
- **Layer rule** — a standing instruction for one stage: set that layer's rules
|
|
10
|
+
- **Project anchor** — a brief, constraint, or style guide that must be in context project-wide: `fs(write, path/o/<org>/projects/<project>/<layer>/<lane>/<file>", content=...)` it, then anchor it so it surfaces on open. [G5]
|
|
11
|
+
- **Attached skill** — a procedure that must be loaded before work: `/drafted:create-skill` (or `fs(search, path/o/<org>/skills", ...)` for an existing one), then attach it to the project. [G4]
|
|
12
|
+
- **Layer rule** — a standing instruction for one stage: set that layer's rules so work in it is gated. [G6]
|
|
13
13
|
3. Propose which mechanism for each correction, confirm with the user, then apply.
|
|
14
14
|
4. Confirm what is now enforced — the next session in this project will be gated on it automatically.
|
|
15
15
|
|
|
@@ -5,10 +5,10 @@ argument-hint: <which skill, and what's off>
|
|
|
5
5
|
|
|
6
6
|
Improve an existing org skill when it underperformed in practice. Skill / issue: $ARGUMENTS
|
|
7
7
|
|
|
8
|
-
1. `
|
|
8
|
+
1. `fs(search, path/o/<org>/skills", query="<slug>")` then `fs(read, path/o/<org>/skills/<slug>")` the skill in question — read it fully.
|
|
9
9
|
2. Pinpoint the inefficiency: a missing step, a wrong instruction, an ambiguous trigger, or a step that wastes effort.
|
|
10
10
|
3. Propose the specific edit to the user — show before/after of the changed steps.
|
|
11
|
-
4. After approval, `
|
|
11
|
+
4. After approval, `fs(write, path/o/<org>/skills/<slug>", content=<updated>)` — writing an existing skill updates it (the version bumps automatically). If it was archived, writing restores it.
|
|
12
12
|
5. Confirm what changed so the next agent benefits.
|
|
13
13
|
|
|
14
14
|
Skills are the org's stable processes — every fix compounds across everyone who uses them.
|
|
@@ -5,10 +5,10 @@ argument-hint: <what's wrong, or the topic to clean up>
|
|
|
5
5
|
|
|
6
6
|
Improve the org wiki when knowledge has drifted. Issue/topic: $ARGUMENTS
|
|
7
7
|
|
|
8
|
-
1. `wiki
|
|
8
|
+
1. `fs(search, path/o/<org>/wiki", query="<terms>")` (3-5 paraphrased queries) and `fs(read, path/o/<org>/wiki/<path>")` the affected pages — don't trust titles, open them.
|
|
9
9
|
2. Diagnose: duplicate pages, a stale fact, a contradiction, or knowledge fragmented across pages.
|
|
10
10
|
3. Propose the fix to the user: consolidate duplicates, correct the fact, reconcile the contradiction, or re-link fragments.
|
|
11
|
-
4. Apply with `wiki
|
|
12
|
-
5. `wiki
|
|
11
|
+
4. Apply with `fs(write, path/o/<org>/wiki/<path>", content=<updated>)` (hashline `edit` for surgical changes) or `fs(mv, path/o/<org>/wiki/<from>", to/o/<org>/wiki/<to>")` (which rewrites inbound links). Check what links to a page before moving or archiving it.
|
|
12
|
+
5. Never hard-delete — `fs(rm, path/o/<org>/wiki/<path>")` moves a page to the archive folder.
|
|
13
13
|
|
|
14
14
|
Leave the wiki more coherent than you found it — fewer, sharper, better-linked pages.
|
|
@@ -12,9 +12,9 @@ First decide WHAT to ingest. If it's obvious from the conversation (a research r
|
|
|
12
12
|
3. **Interrogate the user** (grill-me) — when the knowledge is in their head. Interview relentlessly, walking ONE branch of the decision tree at a time and proposing your recommended answer at each step, until you reach shared understanding. Then structure what you captured.
|
|
13
13
|
|
|
14
14
|
Then deposit:
|
|
15
|
-
- `wiki
|
|
15
|
+
- `fs(search, path/o/<org>/wiki", query="<terms>")` first (3-5 paraphrased queries) so you don't fragment existing pages.
|
|
16
16
|
- Propose the page set to the user before writing.
|
|
17
|
-
- Write with `
|
|
18
|
-
-
|
|
17
|
+
- Write with `fs(write, path/o/<org>/wiki/<path>", content=...)` per page. Cross-link related pages.
|
|
18
|
+
- Confirm what landed where, with the page links.
|
|
19
19
|
|
|
20
20
|
The wiki is the org's durable knowledge — write for the next agent and teammate, not just this session.
|
|
@@ -7,8 +7,8 @@ Onboard the user to Drafted — a producibles harness that compounds across thre
|
|
|
7
7
|
|
|
8
8
|
This is the over-arching prime command: orient, then seed all three stores so every later session starts smart.
|
|
9
9
|
|
|
10
|
-
1. **Orient** — in 3-4 lines explain the loop: you *prime* from the harness (the system makes you search the wiki, and auto-loads the project's attached skills, anchors, and layer rules before you work), you *build*, then you *compound* (deposit what you learned). The more it's used, the less searching and the more stable the work.
|
|
11
|
-
2. **Name the org** —
|
|
10
|
+
1. **Orient** — in 3-4 lines explain the loop: you *prime* from the harness (the system makes you search the wiki, and auto-loads the project's attached skills, anchors, and layer rules before you work), you *build*, then you *compound* (deposit what you learned). The more it's used, the less searching and the more stable the work. Drafted is navigated like a filesystem — one `fs` tool, three roots: `/wiki`, `/skills`, `/projects`.
|
|
11
|
+
2. **Name the org** — the org is an address, not a cursor: address wiki/skills with `org=...` on the call, and projects self-derive their org from the path. Never rely on an "active" org: a project-less create by a multi-org user is refused rather than guessed.
|
|
12
12
|
3. **Seed knowledge** — run the `/drafted:ingest` flow: help the user point at existing business materials (folders, docs, past research) or interrogate them for tacit knowledge, and land durable pages in the wiki.
|
|
13
13
|
4. **Seed procedures** — from those materials and the conversation, surface 1-3 candidate SOPs. For the most valuable, run the `/drafted:create-skill` flow.
|
|
14
14
|
5. **Seed the surface** — run the `/drafted:create-project` flow for the user's immediate piece of work (or a reusable template).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: drafted
|
|
3
|
-
description: Use the Drafted producibles harness — a compounding workspace that uplifts any AI across three primitives: knowledge (the org wiki), procedures (skills), and the project surface (frames on a shared real-time canvas). Prime from the harness before working, build durable artifacts as frames instead of burying output in chat, and deposit what you learned back so the next session starts smarter. When Google Drive is connected, prefer Google Workspace frames for docs, sheets, and slides.
|
|
3
|
+
description: Use the Drafted producibles harness — a compounding workspace that uplifts any AI across three primitives: knowledge (the org wiki), procedures (skills), and the project surface (frames on a shared real-time canvas). Drafted is navigated like a filesystem — one fs tool, one path grammar, org first: `fs(ls, path="/")` lists your orgs, then `/o/<org>/<root>/...`. Prime from the harness before working, build durable artifacts as frames instead of burying output in chat, and deposit what you learned back so the next session starts smarter. When Google Drive is connected, prefer Google Workspace frames for docs, sheets, and slides.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Drafted — a producibles harness that compounds
|
|
@@ -13,33 +13,37 @@ Drafted makes any AI more effective by giving it a memory and a workspace that g
|
|
|
13
13
|
|
|
14
14
|
The point is the **compounding loop**: you don't produce in a vacuum, you draw on what the org already knows and leave it richer each pass.
|
|
15
15
|
|
|
16
|
-
## The
|
|
17
|
-
|
|
18
|
-
- **Prime (session start).** Pull accumulated value in. The system *enforces* this: you must search the wiki before working, and a project's attached skills, anchored frames, and layer rules are auto-loaded when you open it. Don't fight the gates — they make you start smart.
|
|
19
|
-
- **Build (the work).** Produce artifacts as frames on the surface.
|
|
20
|
-
- **Compound (session end / when you notice something).** Deposit learning back: capture knowledge, distill or fix a skill, harden the project. This is *your* responsibility — the system can't force it, so do it.
|
|
16
|
+
## The surface is a filesystem — one tool, one path grammar
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
There is exactly **one** tool to know: `fs`. It looks, feels, and behaves like a local filesystem, and an **org is the top folder** — you address an org, you never switch to it:
|
|
23
19
|
|
|
24
20
|
```
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
fs(ls, path="/") → the orgs you belong to
|
|
22
|
+
fs(ls, path="/o/<org>") → that org's wiki · skills · projects
|
|
23
|
+
/o/<org>/wiki/<path> org knowledge pages (markdown, free nesting)
|
|
24
|
+
/o/<org>/skills/<slug> reusable procedures (flat: one dir per skill)
|
|
25
|
+
/o/<org>/projects/<project>/<layer>/<lane>/<file> frames on the surface (project → layer → lane → file)
|
|
30
26
|
```
|
|
31
27
|
|
|
32
|
-
|
|
28
|
+
Verbs: `ls` (list) · `read` (cat, hashline-annotated) · `write` (create/overwrite) · `edit` (hashline ops) · `mv` (rename/move) · `rm` (move to archive) · `mkdir` (create a project) · `search` (grep).
|
|
29
|
+
|
|
30
|
+
**A project is a folder.** It starts with **no layers** — writing to `/o/<org>/projects/<name>/<layer>/...` auto-creates the layer (mkdir -p). The agent defines the filesystem structure by writing into it. URLs are the same paths: `https://drafted.live/o/<org>/projects/<project>/<layer>/<lane>/<file>` — the URL's pathname IS the fs path (one canonical link for both humans and agents). Bare `/wiki`, `/skills`, `/projects` roots still work via the session's working org.
|
|
31
|
+
|
|
32
|
+
## The loop — prime → build → compound
|
|
33
|
+
|
|
34
|
+
- **Prime (session start).** Pull accumulated value in. The system *enforces* this: you must search the wiki before working (G1), and a project's attached skills and anchored frames are required reading when you open it. Don't fight the gates — they make you start smart.
|
|
35
|
+
- **Build (the work).** Produce artifacts as frames on the surface.
|
|
36
|
+
- **Compound (session end / when you notice something).** Deposit learning back: capture knowledge, distill or fix a skill, harden the project. This is *your* responsibility — the system can't force it, so do it.
|
|
33
37
|
|
|
34
38
|
## The gates you'll encounter (and how to satisfy them)
|
|
35
39
|
|
|
36
40
|
These reset every session. A gate that blocks you tells you exactly what to call next — do it, don't work around it.
|
|
37
41
|
|
|
38
|
-
- **G1 — wiki search before work.** Before
|
|
39
|
-
- **G2 — prior-art before a new skill.** `
|
|
40
|
-
- **G3 — prior-art before a new project.**
|
|
42
|
+
- **G1 — wiki search before work.** Before reading or editing anything, `fs(search, path="/o/<org>/wiki", query="<terms>")` for relevant org knowledge.
|
|
43
|
+
- **G2 — prior-art before a new skill.** Writing a new `/o/<org>/skills/<slug>` requires `fs(search, path="/o/<org>/skills", query="<topic>")` first.
|
|
44
|
+
- **G3 — prior-art before a new project.** Creating a project requires wiki + skill searches first.
|
|
41
45
|
- **G4 — attached skills** are auto-injected when you open a project. Follow them — they're how the org does this work.
|
|
42
|
-
- **G5 — the project's anchored frames** are
|
|
46
|
+
- **G5 — the project's anchored frames** are required reading (briefs, constraints, style guides).
|
|
43
47
|
- **G6 — a layer's rules** are surfaced when you work in that layer. Honor them.
|
|
44
48
|
|
|
45
49
|
## The commands (when to reach for each)
|
|
@@ -55,30 +59,30 @@ These bookend the loop. Prime/feed at the start, deposit at the end.
|
|
|
55
59
|
- `/drafted:improve-project-harness` — turn corrections into enforced gates (anchors / attached skills / layer rules).
|
|
56
60
|
- `/drafted:extract` — session-end: deposit knowledge, a skill, and/or a template (the user picks which).
|
|
57
61
|
|
|
58
|
-
## Tool surface (action-based)
|
|
59
|
-
|
|
60
|
-
`project(list|open|create|update|move)` · `frame(read|write|edit|anchor|mv|search|…)` · `ls` · `skill(search|load|list|add|update|attach|…)` · `wiki(search|read|write|edit|mv|links|log|…)` · `template(list|create|fork|…)` · `focus` · `get_org` · `asset` · `layer`.
|
|
61
|
-
|
|
62
|
-
## Sign in
|
|
63
|
-
|
|
64
|
-
If a tool returns an auth error: on a desktop/CLI agent run the `auth(action="login")` tool (it prints a one-time URL; the user opens it). On the web/Cowork connector, authorization happens via the connector's OAuth — ask the user to re-authorize the Drafted connector in their settings, then retry.
|
|
65
|
-
|
|
66
62
|
## Working on the surface
|
|
67
63
|
|
|
68
|
-
- **
|
|
64
|
+
- **Navigate by path, exactly like a filesystem.** `fs(ls, path="/")` to see your orgs; `fs(ls, path="/o/<org>/projects")` to see a project list; `fs(ls, path="/o/<org>/projects/<project>")` for layers/lanes; `fs(ls, path="/o/<org>/projects/<project>/<layer>")` for frames. The project is resolved from the path itself — no separate "open" step.
|
|
65
|
+
- **Create a project with `fs(mkdir, path="/o/<org>/projects/<name>")`** — or just `fs(write, path="/o/<org>/projects/<name>/<layer>/<lane>/<file>", content=...)` and the project + layer auto-create in the addressed org.
|
|
69
66
|
- **Default to the surface for substantive artifacts.** When asked to draft, write, plan, analyze, compare, design, document, summarize, report, spec, model, or make a deck/table, create or update frames instead of leaving the durable result only in chat. One visible frame per artifact or section.
|
|
70
|
-
- **
|
|
71
|
-
- **
|
|
72
|
-
- **`
|
|
67
|
+
- **Read before editing.** `fs(read)` returns every line hashline-annotated (`1abc|<content>`); `fs(edit, ops=[{type:"replace", lineHash:"1abc", newContent:"..."}])` targets exactly that line. For partial reads, pass `lines: "2-50"` — you get back just that range, still hash-annotated, and can edit within it.
|
|
68
|
+
- **Prefer Google Workspace when Drive is connected.** Use `fs(write, path=".../<name>.google-doc"|".google-sheet"|".google-slide")` for docs, sheets, and decks; populate immediately with the matching native write action.
|
|
69
|
+
- **`fs(mv, from="/o/<org>/projects/<p>/<layer>/<lane>/<file>", to="...")`** renames or moves (cross-project too). **`fs(rm, path="/o/<org>/projects/<project>")` archives** — agents never hard-delete; the archive is in the web UI.
|
|
70
|
+
- **Return a clickable link** for what you touched — the `frameUrl`/`projectUrl` in the fs response is the URL the user opens.
|
|
73
71
|
|
|
74
72
|
## Quality conventions
|
|
75
73
|
|
|
76
74
|
- **Match format to layer intent.** Research/strategy/copy are usually markdown; visual work (wireframes, designs, dashboards) is HTML.
|
|
77
|
-
- **Respect the template's conventions.** Read a `design-system` layer before `/designs/`; read an `audience` layer before `/copy/`.
|
|
78
75
|
- **Wireframes are low-fidelity** (grayscale, placeholders); reserve color and real content for the designs/final layer.
|
|
79
76
|
- **Choose dimensions to fit content** — `autoSize: true` for HTML, or explicit `width`/`height`.
|
|
80
77
|
- **Don't re-read unchanged frames** you already have this conversation.
|
|
78
|
+
- **Diagrams: prefer native Excalidraw.** For flowcharts, process maps, architecture/system/data-flow diagrams, or visual maps, write a `.excalidraw` file (scene JSON) and load the `excalidraw-drafted` skill for the authoring guidance. Use HTML/markdown frames for web/UI mockups, rich layouts, or non-editable artifacts.
|
|
79
|
+
|
|
80
|
+
## Skill authoring
|
|
81
|
+
|
|
82
|
+
- **Author reusable skills in Drafted, not just the local repo.** The portable part — the method, SKILL.md, and script source — belongs in the Drafted skill library: `fs(write, path="/o/<org>/skills/<slug>", content=...)` for a new skill (G2 gate first), or `fs(mv, path="/o/<org>/skills/<old>", to="/o/<org>/skills/<new>")` to rename. Declare how to rebuild in the skill's `setup:` frontmatter so any machine or agent can regenerate it.
|
|
83
|
+
- **Machine-specific build output is never portable.** Build `node_modules`, downloaded browsers, compiled binaries into a `.skillinstall/` directory inside the skill — Drafted always strips it on push and skill push auto-gitignores it, so the rebuildable bundle stays local while the method and recipe live in Drafted.
|
|
84
|
+
- **Improve skills when you find a better way.** Fix or distill a skill that underperformed rather than leaving it stale.
|
|
81
85
|
|
|
82
86
|
## Surface URL recognition
|
|
83
87
|
|
|
84
|
-
Any URL containing `/f/{uuid}` is a Drafted frame link
|
|
88
|
+
Any URL containing `/f/{uuid}` is a Drafted frame link — `fs(read, path=URL)` gets its content. Canonical links are the fs paths themselves: `/o/<org>/wiki/...`, `/o/<org>/skills/<slug>`, `/o/<org>/projects/<project>/<layer>/<lane>/<file>`. Never `WebFetch` Drafted URLs — the MCP tools authenticate properly.
|
package/src/shared/constants.mjs
CHANGED
|
@@ -22,7 +22,7 @@ export const LAYERS = {
|
|
|
22
22
|
|
|
23
23
|
// File extensions recognized per layer
|
|
24
24
|
export const DESIGN_EXTENSIONS = new Set(['.html', '.htm']);
|
|
25
|
-
export const DOC_EXTENSIONS = new Set(['.md', '.txt']);
|
|
25
|
+
export const DOC_EXTENSIONS = new Set(['.md', '.txt', '.json', '.csv', '.yaml', '.yml', '.jsonl']);
|
|
26
26
|
export const EXCALIDRAW_EXTENSIONS = new Set(['.excalidraw']);
|
|
27
27
|
export const ASSET_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.pdf', '.mp4', '.webm', '.mov', '.m4v']);
|
|
28
28
|
|