editorbrain 0.9.0 → 0.10.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/README.md +2 -2
- package/bin/editorbrain.mjs +95 -7
- package/package.json +1 -1
- package/skill/editorbrain/AGENTS.md +2 -0
- package/skill/editorbrain/SKILL.md +3 -1
- package/skill/editorbrain/references/cli-mcp.md +4 -0
- package/skill/editorbrain/references/memory-and-review.md +91 -0
- package/skill/editorbrain/references/workspace-files.md +7 -2
package/README.md
CHANGED
|
@@ -5,13 +5,13 @@ Editorial references, brand context and portable video projects for Claude Code
|
|
|
5
5
|
Inspect the CLI without configuring your agent:
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
npx editorbrain@0.
|
|
8
|
+
npx editorbrain@0.10.0 help
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
For a persistent installation:
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
|
-
npm install -g editorbrain@0.
|
|
14
|
+
npm install -g editorbrain@0.10.0
|
|
15
15
|
editorbrain login --url https://api.editorbrain.com
|
|
16
16
|
editorbrain status --url https://api.editorbrain.com
|
|
17
17
|
editorbrain projects list
|
package/bin/editorbrain.mjs
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// packages/core/src/memory.ts
|
|
4
|
+
function memoryPath(scope, id) {
|
|
5
|
+
if (!["brand", "style", "project"].includes(scope) || !/^[a-z0-9][a-z0-9_-]{0,79}$/.test(id)) throw new Error("Invalid memory scope");
|
|
6
|
+
return scope === "project" ? `videos/${id}/preferences.json` : `.editorbrain/${scope === "brand" ? "brands" : "styles"}/${id}/preferences.json`;
|
|
7
|
+
}
|
|
8
|
+
function memoryScope(path) {
|
|
9
|
+
const m = path.match(/^\.editorbrain\/(brands|styles)\/([a-z0-9_-]+)\/preferences\.json$/), p = path.match(/^videos\/([a-z0-9_-]+)\/preferences\.json$/);
|
|
10
|
+
return m ? { scope: m[1] === "brands" ? "brand" : "style", scopeId: m[2] } : p ? { scope: "project", scopeId: p[1] } : null;
|
|
11
|
+
}
|
|
12
|
+
function memoryIssues(path, doc) {
|
|
13
|
+
const scope = memoryScope(path);
|
|
14
|
+
if (!scope) return [];
|
|
15
|
+
if (doc.scope !== scope.scope || doc.scopeId !== scope.scopeId || !Array.isArray(doc.entries) || doc.entries.length > 60) return ["Memory requires matching scope and at most 60 entries"];
|
|
16
|
+
const ids = /* @__PURE__ */ new Set();
|
|
17
|
+
const errors = [];
|
|
18
|
+
for (const e of doc.entries) {
|
|
19
|
+
if (!e || typeof e.id !== "string" || !/^[a-zA-Z0-9_-]{1,100}$/.test(e.id) || ids.has(e.id) || typeof e.text !== "string" || !e.text.trim() || e.text.length > 800 || typeof e.conditions !== "string" || e.conditions.length > 400 || !["suggested", "confirmed", "disabled"].includes(e.status) || typeof e.source !== "string" || e.source.length > 400 || !["agent_reported", "user_saved", "weekly_proposal"].includes(e.provenance) || typeof e.updatedAt !== "string" || !Number.isFinite(Date.parse(e.updatedAt))) errors.push("Invalid or duplicate memory entry");
|
|
20
|
+
ids.add(e?.id);
|
|
21
|
+
}
|
|
22
|
+
return errors;
|
|
23
|
+
}
|
|
24
|
+
function resolveMemory(files, p) {
|
|
25
|
+
const entries = [["style", p.style], ["brand", p.brand], ["project", p.id]].flatMap(([scope, id]) => {
|
|
26
|
+
const path = memoryPath(scope, id);
|
|
27
|
+
if (!files[path]) return [];
|
|
28
|
+
return JSON.parse(files[path]).entries.map((e) => ({ ...e, scope, scopeId: id, path }));
|
|
29
|
+
});
|
|
30
|
+
return { confirmed: entries.filter((e) => e.status === "confirmed"), pending: entries.filter((e) => e.status === "suggested").map(({ id, scope, scopeId }) => ({ id, scope, scopeId })), policy: "Apply only relevant confirmed preferences. Conditions and prose conflicts require agent judgment. Project-specific guidance precedes brand then style; required tokens still govern. Suggestions are not instructions. Provenance is a claim, not proof of human confirmation." };
|
|
31
|
+
}
|
|
32
|
+
|
|
3
33
|
// packages/core/src/index.ts
|
|
4
34
|
var SCHEMA_VERSION = 1;
|
|
5
35
|
var MAX_DOCUMENT_BYTES = 128 * 1024;
|
|
@@ -80,6 +110,7 @@ function validateDocument(path, content) {
|
|
|
80
110
|
return { valid: false, issues };
|
|
81
111
|
}
|
|
82
112
|
if (doc.schemaVersion !== SCHEMA_VERSION) add("schemaVersion must be 1");
|
|
113
|
+
for (const message of memoryIssues(canonicalDocumentPath(path), doc)) add(message);
|
|
83
114
|
const parts = canonicalDocumentPath(path).split("/");
|
|
84
115
|
const isBrand = parts[0] === ".editorbrain" && parts[1] === "brands" && parts.length === 4;
|
|
85
116
|
const isStyle = parts[0] === ".editorbrain" && parts[1] === "styles" && parts.length === 4;
|
|
@@ -154,7 +185,7 @@ function projectSources(project) {
|
|
|
154
185
|
];
|
|
155
186
|
}
|
|
156
187
|
function optionalProjectSources(project) {
|
|
157
|
-
return [`.editorbrain/brands/${project.brand}/design.md`, `.editorbrain/styles/${project.style}/effects.md`, `.editorbrain/styles/${project.style}/music.md`, `videos/${project.id}/media.json
|
|
188
|
+
return [`.editorbrain/brands/${project.brand}/design.md`, `.editorbrain/styles/${project.style}/effects.md`, `.editorbrain/styles/${project.style}/music.md`, `videos/${project.id}/media.json`, memoryPath("brand", project.brand), memoryPath("style", project.style), memoryPath("project", project.id)];
|
|
158
189
|
}
|
|
159
190
|
function validateWorkspace(files) {
|
|
160
191
|
files = canonicalFiles(files);
|
|
@@ -233,6 +264,7 @@ async function resolveProject(files, projectId) {
|
|
|
233
264
|
brandAssets: JSON.parse(files[assetsPath]),
|
|
234
265
|
examples: JSON.parse(files[examplesPath]),
|
|
235
266
|
...own(files, optionalPaths[3]) ? { media: JSON.parse(files[optionalPaths[3]]) } : {},
|
|
267
|
+
memory: resolveMemory(files, project),
|
|
236
268
|
evidence: style.references ?? [],
|
|
237
269
|
warnings,
|
|
238
270
|
lock: { schemaVersion: 1, projectId, sourceHashes, overrides: project.overrides ?? {}, adapters: Object.fromEntries(["neutral", "hyperframes", "remotion"].map((key) => [key, { version: "0.2.1", kind: "editorial_handoff", rendered: false }])) }
|
|
@@ -777,7 +809,7 @@ import { createHash } from "node:crypto";
|
|
|
777
809
|
import { constants as constants2 } from "node:fs";
|
|
778
810
|
import { lstat as lstat2, open as open2, readdir as readdir2, rename as rename2 } from "node:fs/promises";
|
|
779
811
|
import { fileURLToPath } from "node:url";
|
|
780
|
-
var previousSkillHashes = { "SKILL.md": ["9df2c89deeec30ddf556c359027efe1d90e6b4e9c08717cd8827e210b38a187f", "67b157cb45cae3621e6f2c43235c1d69907ad6abd45ab6b52a3c65f236732db9", "1e2fff65a1b303b18b2d65156bef6eb2439a19d77ba2a25b37bcb1819ff009e3"], "AGENTS.md": ["4f3ef860ade3a31aa7c6a6aab5cf6ec2a700850bf19ea2320324c12c2e0fbf5b", "1b07de01698a0040b47ea0eddb1b017f70a69e81acd0bf9710647ca5e02f5125", "b5ee3439ff974c668755816149fab76899d7ad9266f63978b30fbc9b7d2cd640"], "references/cli-mcp.md": ["5d3a79343fbd76cdae5bdbe12fb9c944d5dff4f489ac6534fd96e0cb8630b988", "8e011c31368cef2117a28ee972b39aab9535eeb0f601a4a0f9d6fc019b22c1c2", "666082653efc000f8a7cc5f1836c80bbdda5f0f57cdbbdcb393f2b84aeb93a01", "78b737796a8685b1135e0acb91b620c51845b62e31dba04eb51dd9dd38b41008"], "references/production-and-review.md": ["055c6df9e0f167be148b0a5c0bba5b43e108eb1f58f478d88b3536c6589ac7b3"], "references/workspace-files.md": ["e72af2871f42cd776be1bfff8009ed5562780e7f8a65b12c27887f3880631f81", "00780c64bd0244c6afb18d786b7512b43e315c376e8f88c67d6ba53d91275ccf", "97053b092e0ff36e3cfb764095fcb4a4fca94e722567e774b53bc118279f40e5"] };
|
|
812
|
+
var previousSkillHashes = { "SKILL.md": ["9df2c89deeec30ddf556c359027efe1d90e6b4e9c08717cd8827e210b38a187f", "67b157cb45cae3621e6f2c43235c1d69907ad6abd45ab6b52a3c65f236732db9", "1e2fff65a1b303b18b2d65156bef6eb2439a19d77ba2a25b37bcb1819ff009e3", "dacce1c4127f4281df6f7e1681e243444bb6f8a8e74b829e52ee0108c6672348"], "AGENTS.md": ["4f3ef860ade3a31aa7c6a6aab5cf6ec2a700850bf19ea2320324c12c2e0fbf5b", "1b07de01698a0040b47ea0eddb1b017f70a69e81acd0bf9710647ca5e02f5125", "b5ee3439ff974c668755816149fab76899d7ad9266f63978b30fbc9b7d2cd640", "bacedb7bdedab5abe75c9601717cfdb05a96208fa2e2a42af878e2dfd2ae4251"], "references/cli-mcp.md": ["5d3a79343fbd76cdae5bdbe12fb9c944d5dff4f489ac6534fd96e0cb8630b988", "8e011c31368cef2117a28ee972b39aab9535eeb0f601a4a0f9d6fc019b22c1c2", "666082653efc000f8a7cc5f1836c80bbdda5f0f57cdbbdcb393f2b84aeb93a01", "78b737796a8685b1135e0acb91b620c51845b62e31dba04eb51dd9dd38b41008", "8b2e01bfd937237919f5ade794eed01dc6e32b556ede9de3a0ccc28cbdd988d1"], "references/production-and-review.md": ["055c6df9e0f167be148b0a5c0bba5b43e108eb1f58f478d88b3536c6589ac7b3"], "references/workspace-files.md": ["e72af2871f42cd776be1bfff8009ed5562780e7f8a65b12c27887f3880631f81", "00780c64bd0244c6afb18d786b7512b43e315c376e8f88c67d6ba53d91275ccf", "97053b092e0ff36e3cfb764095fcb4a4fca94e722567e774b53bc118279f40e5", "70fc660e7ed3d70c16c33c62c8e0399b99c3251808f093ef3d4ea5e8d39e4c8a"] };
|
|
781
813
|
var destinations = {
|
|
782
814
|
codex: { directory: ".agents/skills/editorbrain", entryPoint: "AGENTS.md" },
|
|
783
815
|
claude: { directory: ".claude/skills/editorbrain", entryPoint: "CLAUDE.md" }
|
|
@@ -1361,7 +1393,18 @@ editorbrain pull [--project id | --all] [--dir folder] [--dry-run]
|
|
|
1361
1393
|
editorbrain push [--dir folder] [--dry-run]
|
|
1362
1394
|
editorbrain projects list
|
|
1363
1395
|
editorbrain documents list [--prefix path]
|
|
1364
|
-
editorbrain documents get <path>
|
|
1396
|
+
editorbrain documents get <path> [--revision N]
|
|
1397
|
+
editorbrain documents history <path> [--before N]
|
|
1398
|
+
editorbrain documents restore <path> --revision N --expected-revision N
|
|
1399
|
+
editorbrain memory list --scope brand|style|project --id ID
|
|
1400
|
+
editorbrain memory add --scope brand|style|project --id ID --text TEXT --status suggested|confirmed --expected-revision N
|
|
1401
|
+
editorbrain memory confirm|disable ENTRY --scope brand|style|project --id ID --expected-revision N
|
|
1402
|
+
editorbrain feedback add --project ID --text TEXT
|
|
1403
|
+
editorbrain improvements list --brand ID
|
|
1404
|
+
editorbrain improvements accept RUN --index N --expected-revision N
|
|
1405
|
+
editorbrain review list --project ID
|
|
1406
|
+
editorbrain review create --project ID --asset SHA --title TEXT --kind sample|render --days 7 --share-authorized
|
|
1407
|
+
editorbrain review revoke ID
|
|
1365
1408
|
editorbrain workflow check [--project id] [--previous-version hash]
|
|
1366
1409
|
editorbrain search brief --file <editorial-brief.json> [--project id] [--mode styles|events|both] [--review direct|directions|sample]
|
|
1367
1410
|
editorbrain search edit [--script file | --video file | --asset sha256 | --project id] [--requirements text] [--assets tag,tag] [--mode styles|events|both] [--review direct|directions|sample]
|
|
@@ -1391,8 +1434,8 @@ Output is JSON except help; login progress/code goes to stderr. --url overrides
|
|
|
1391
1434
|
function parseArgs(argv) {
|
|
1392
1435
|
const positional = [];
|
|
1393
1436
|
const flags = {};
|
|
1394
|
-
const booleans = /* @__PURE__ */ new Set(["help", "version", "offline", "dry-run", "key-stdin", "invite-stdin", "no-browser", "skip-mcp", "all"]);
|
|
1395
|
-
const known = /* @__PURE__ */ new Set(["dir", "brand", "style", "project", "topic", "goal", "name", "adapter", "out", "url", "document", "mime", "label", "role", "limit", "cursor", "timeout", "assets", "capabilities", "duration", "agent", "workspace", "prefix", "sha256", "kind", "channel", "epistemic-status", "event-offset", "relation-offset", "script", "video", "asset", "requirements", "mode", "review", "previous-version", "file", ...booleans]);
|
|
1437
|
+
const booleans = /* @__PURE__ */ new Set(["help", "version", "offline", "dry-run", "key-stdin", "invite-stdin", "no-browser", "skip-mcp", "all", "share-authorized"]);
|
|
1438
|
+
const known = /* @__PURE__ */ new Set(["dir", "brand", "style", "project", "topic", "goal", "name", "adapter", "out", "url", "document", "mime", "label", "role", "limit", "cursor", "timeout", "assets", "capabilities", "duration", "agent", "workspace", "prefix", "sha256", "kind", "channel", "epistemic-status", "event-offset", "relation-offset", "script", "video", "asset", "requirements", "mode", "review", "previous-version", "file", "revision", "expected-revision", "before", "scope", "id", "text", "conditions", "status", "index", "title", "days", ...booleans]);
|
|
1396
1439
|
for (let i = 0; i < argv.length; i++) {
|
|
1397
1440
|
const arg = argv[i];
|
|
1398
1441
|
if (!arg.startsWith("--")) {
|
|
@@ -1667,12 +1710,57 @@ async function main() {
|
|
|
1667
1710
|
return;
|
|
1668
1711
|
}
|
|
1669
1712
|
if (subcommand === "get" && argument) {
|
|
1670
|
-
const doc = await client.
|
|
1713
|
+
const doc = await client.request(`/v1/documents/${argument.split("/").map(encodeURIComponent).join("/")}${str(args, "revision") ? "?revision=" + encodeURIComponent(str(args, "revision")) : ""}`);
|
|
1671
1714
|
if (await sha256(doc.content) !== doc.sha256) throw new Error("Document integrity failed");
|
|
1672
1715
|
output(doc);
|
|
1673
1716
|
return;
|
|
1674
1717
|
}
|
|
1675
|
-
|
|
1718
|
+
if (subcommand === "history" && argument) {
|
|
1719
|
+
output(await client.request("/v1/history?" + new URLSearchParams({ path: argument, ...str(args, "before") ? { before: str(args, "before") } : {} })));
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
if (subcommand === "restore" && argument) {
|
|
1723
|
+
output(await client.request("/v1/history/restore", { method: "POST", body: { path: argument, revision: Number(str(args, "revision")), expectedRevision: Number(str(args, "expected-revision")) } }));
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1726
|
+
throw new Error("Use documents list/get/history/restore. Restore requires --revision and --expected-revision.");
|
|
1727
|
+
}
|
|
1728
|
+
if (command === "memory" || command === "feedback" || command === "review" || command === "improvements") {
|
|
1729
|
+
const client = new Client(await config(args));
|
|
1730
|
+
if (command === "memory" && subcommand === "list") {
|
|
1731
|
+
output(await client.request("/v1/memory?" + new URLSearchParams({ scope: str(args, "scope") ?? "brand", scopeId: str(args, "id") ?? "" })));
|
|
1732
|
+
return;
|
|
1733
|
+
}
|
|
1734
|
+
if (command === "memory" && ["add", "confirm", "disable"].includes(subcommand ?? "")) {
|
|
1735
|
+
output(await client.request("/v1/memory", { method: "POST", body: { scope: str(args, "scope") ?? "brand", scopeId: str(args, "id"), action: subcommand, entryId: argument, expectedRevision: Number(str(args, "expected-revision")), text: str(args, "text"), conditions: str(args, "conditions") ?? "", status: str(args, "status") ?? "suggested" } }));
|
|
1736
|
+
return;
|
|
1737
|
+
}
|
|
1738
|
+
if (command === "feedback" && subcommand === "add") {
|
|
1739
|
+
output(await client.request("/v1/feedback", { method: "POST", body: { projectId: str(args, "project"), text: str(args, "text") } }));
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1742
|
+
if (command === "improvements" && subcommand === "list") {
|
|
1743
|
+
output(await client.request("/v1/improvements?" + new URLSearchParams({ brandId: str(args, "brand") ?? "" })));
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
if (command === "improvements" && subcommand === "accept") {
|
|
1747
|
+
output(await client.request("/v1/improvements/accept", { method: "POST", body: { runId: argument, index: Number(str(args, "index")), expectedRevision: Number(str(args, "expected-revision")) } }));
|
|
1748
|
+
return;
|
|
1749
|
+
}
|
|
1750
|
+
if (command === "review" && subcommand === "list") {
|
|
1751
|
+
output(await client.request("/v1/reviews?" + new URLSearchParams({ projectId: str(args, "project") ?? "" })));
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
if (command === "review" && subcommand === "revoke" && argument) {
|
|
1755
|
+
output(await client.request("/v1/reviews/" + encodeURIComponent(argument), { method: "DELETE" }));
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1758
|
+
if (command === "review" && subcommand === "create") {
|
|
1759
|
+
if (!args.flags["share-authorized"]) throw new Error("Sharing requires explicit user authorization and --share-authorized. Anyone with the link can view.");
|
|
1760
|
+
output(await client.request("/v1/reviews", { method: "POST", body: { projectId: str(args, "project"), assetId: str(args, "asset"), title: str(args, "title"), kind: str(args, "kind") ?? "sample", days: Number(str(args, "days") ?? 7), shareAuthorized: true } }));
|
|
1761
|
+
return;
|
|
1762
|
+
}
|
|
1763
|
+
throw new Error("Use memory list/add/confirm/disable, feedback add, improvements list/accept, review list/create/revoke. See help for flags.");
|
|
1676
1764
|
}
|
|
1677
1765
|
if (command === "assets") {
|
|
1678
1766
|
const client = new Client(await config(args));
|
package/package.json
CHANGED
|
@@ -73,6 +73,8 @@ Separate these levels:
|
|
|
73
73
|
2. **Conditional technique requirements:** a matte follows its subject if used; synchronized text aligns if chosen; a functional UI has meaningful states if depicted.
|
|
74
74
|
3. **Project/preset preferences:** particular colors, click patterns, monochrome treatment, density or source choices.
|
|
75
75
|
|
|
76
|
+
At workflow checkpoints, read `context.memory.confirmed` and its conditions; compare `context.contextVersion` before costly work. Refresh changed source documents without overwriting local changes. Suggestions are not applied preferences; prose memory never bypasses required tokens. Read [memory and review](references/memory-and-review.md) when saving feedback, accepting proposals, restoring history or sharing a specific artifact.
|
|
77
|
+
|
|
76
78
|
Do not convert a single video's feedback into a global ban, fixed source quota or mandatory sound. Record feedback at its stated scope; ask only when that scope materially changes other work. Approval of one production does not prove transfer quality in every niche.
|
|
77
79
|
|
|
78
80
|
Preserve previous versions and save the references used, adaptations, source plan, effective parameters, review results and user feedback with their project/version. Reuse existing formats; optional production notes may live under `videos/<project-id>/`. Do not invent mandatory files that the CLI cannot validate.
|
|
@@ -11,13 +11,15 @@ You are the editor. EditorBrain supplies the harness: persistent brand/style/pro
|
|
|
11
11
|
|
|
12
12
|
1. Read the bundled [AGENTS.md](AGENTS.md) once for the editorial contract. Do not assume the host loads this nested file automatically.
|
|
13
13
|
2. If no workspace is ready, use [first edit](references/first-edit.md). Verify connection, discover or create the active project, and prepare its context without overwriting existing files. Read [CLI and MCP](references/cli-mcp.md) only for the commands needed now.
|
|
14
|
-
3. Read the selected project's `project.json`, brief, direction and the brand/style files it names. Resolve effective tokens and inspect available editing tools. Use `check_workflow` (CLI `editorbrain workflow check`) for the current review preference. Do not load every project or library document.
|
|
14
|
+
3. Read the selected project's `project.json`, brief, direction and the brand/style files it names. Resolve effective tokens and inspect available editing tools. Use `check_workflow` (CLI `editorbrain workflow check`) for the current review preference and confirmed scoped memory. Compare `contextVersion` at later checkpoints; fetch changed files before acting. Do not load every project or library document.
|
|
15
15
|
4. Inspect the actual script/video yourself. Understand its argument, goal, audience, tone, rhythm, usable resources and brand restrictions. Declare what you could inspect: script, frames, motion, audio and coverage. If you cannot access a modality, keep the limitation explicit; never invent it from a filename.
|
|
16
16
|
5. Use `search_from_brief` (CLI `editorbrain search brief --file <brief.json>`) with your analysis and project ID. Read [search brief](references/search-brief.md) for its schema. Search editorial mechanisms as well as the subject. The server returns evidence candidates using embeddings; it does not analyze the source again or certify fit. `search_for_edit` is an optional older server-analysis path, only when explicitly requested; never silently fall back to it.
|
|
17
17
|
6. Compare the candidates yourself. View the relevant reference frames; inspect intervals and audio when movement or sound matters. Select what fits the actual material, explain adaptations and missing resources, and save the direction with source hashes. Similarity is not approval; reject weak matches instead of forcing them.
|
|
18
18
|
7. Follow the effective review mode: `direct` → implement and review; `directions` → propose suitable alternatives with labelled reference evidence; `sample` → show a frame/short clip made with customer material before the full edit. Respect existing approval. Check the preference version before proposals, costly generation and full rendering; a web update cannot interrupt an active tool.
|
|
19
19
|
8. Implement with available editing/rendering tools, then inspect the final artifact and save scoped feedback. An editing request needs the edit, not only a plan. Read [production and review](references/production-and-review.md) for complex motion, audio or transfer QA. Report any dimension you could not verify.
|
|
20
20
|
|
|
21
|
+
For feedback, accepted memory, weekly proposals, document restore or explicitly requested sharing, read [memory and review](references/memory-and-review.md). Weekly suggestions never become instructions until accepted.
|
|
22
|
+
|
|
21
23
|
Use [workspace files](references/workspace-files.md) when changing branding/styles or saving feedback. Keep `design.md`, `effects.md` and `music.md` editable at their own scopes; they guide coherent choices, not identical edits for every topic. Preserve customized instructions and previous versions. Fetch further evidence only to answer a concrete editing question.
|
|
22
24
|
|
|
23
25
|
Public web: https://editorbrain.com. CLI/package/skill: `editorbrain`. MCP: https://api.editorbrain.com/mcp. Source analysis by you, library retrieval by EditorBrain, selection and execution by you. A retrieved reference, export or model opinion does not certify render quality.
|
|
@@ -147,3 +147,7 @@ editorbrain workflow check --project my-video --previous-version <returned-hash>
|
|
|
147
147
|
MCP equivalents: `check_workflow` and `search_from_brief`. Search returns candidate evidence; you inspect it, compare applicability, choose and implement. It does not upload or re-analyze your source video. Older `search_for_edit` / `search edit` remains compatible as an explicitly chosen server-analysis option; it is not the default and must not be an automatic fallback.
|
|
148
148
|
|
|
149
149
|
Web preferences are pulled at checkpoints, not pushed into arbitrary agent chats. A receipt acknowledges reading; it cannot stop a running tool. Reconcile relevant changes before the next step. Respect existing scoped approval. Server timing/token telemetry excludes the host agent's own work.
|
|
150
|
+
|
|
151
|
+
## Memory, history and review links (0.10+)
|
|
152
|
+
|
|
153
|
+
Read [memory and review](memory-and-review.md) when needed. CLI commands `memory`, `feedback`, `improvements`, `documents history/restore` and `review` map to the corresponding scoped MCP tools. Memory/restore mutations require current revisions. Sharing requires explicit authorization and a project-linked own asset.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Editorial memory, history and reviews
|
|
2
|
+
|
|
3
|
+
## Read only the selected context
|
|
4
|
+
|
|
5
|
+
`check_workflow` / `editorbrain workflow check --project ID` returns `context.memory`,
|
|
6
|
+
`context.sourceHashes`, and `context.contextVersion`. The version is distinct from
|
|
7
|
+
workflow preference `version`. Compare both at the start and before proposals, paid
|
|
8
|
+
generation and final render. A changed context requires rereading affected documents;
|
|
9
|
+
it does not justify overwriting local work. Offline edits cannot see new web changes.
|
|
10
|
+
`resolve` and `search_from_brief` also include scoped memory.
|
|
11
|
+
|
|
12
|
+
Optional portable memory paths:
|
|
13
|
+
- Brand: `.editorbrain/brands/<id>/preferences.json`
|
|
14
|
+
- Style: `.editorbrain/styles/<id>/preferences.json`
|
|
15
|
+
- Project: `videos/<id>/preferences.json`
|
|
16
|
+
|
|
17
|
+
Each contains `schemaVersion:1`, matching `scope` (`brand`, `style`, `project`),
|
|
18
|
+
`scopeId` and up to 60 `entries`. Each entry has `id`, `text`, `conditions`, `status`
|
|
19
|
+
(`suggested`, `confirmed`, `disabled`), `source`, `provenance` and `updatedAt`.
|
|
20
|
+
The API validates these and provides IDs and timestamps. Prefer its memory tools.
|
|
21
|
+
Confirmed entries guide choices only when their conditions fit. Project guidance
|
|
22
|
+
precedes brand then style; exact required tokens still govern. Resolve prose conflicts
|
|
23
|
+
using the actual user request. `provenance` records a claim, not proof of human approval.
|
|
24
|
+
Suggestions and disabled entries are not editing instructions.
|
|
25
|
+
|
|
26
|
+
Legacy `.editorbrain/memory/preferences.json` is preserved and not resolved. If relevant,
|
|
27
|
+
inspect it and migrate only clearly scoped, confirmed preferences with the user's intent;
|
|
28
|
+
do not silently apply old unscoped notes to all brands.
|
|
29
|
+
|
|
30
|
+
## Save feedback without inventing approval
|
|
31
|
+
|
|
32
|
+
`save_editorial_feedback({projectId,text})` / `editorbrain feedback add --project ID --text TEXT`
|
|
33
|
+
saves an observation, not a reusable rule. The server derives the brand from the project.
|
|
34
|
+
Identical notes for one project/day are deduplicated. Maximum 500 notes/workspace/7 days.
|
|
35
|
+
Keep actual customer feedback distinct from your own QA and identify it in the text.
|
|
36
|
+
Do not manufacture feedback to activate a weekly analysis.
|
|
37
|
+
|
|
38
|
+
Read `get_editorial_memory({scope,scopeId})` / `editorbrain memory list --scope brand --id ID`
|
|
39
|
+
for the current document revision. `save_editorial_memory` supports:
|
|
40
|
+
- `action:add`, `text`, optional `conditions`, explicit `status:suggested|confirmed`.
|
|
41
|
+
- `action:confirm|disable`, `entryId`.
|
|
42
|
+
All changes require `scope`, `scopeId`, `expectedRevision` (0 creates).
|
|
43
|
+
CLI equivalents: `memory add --text TEXT --conditions TEXT --status suggested --expected-revision N`
|
|
44
|
+
or `memory confirm|disable ENTRY --expected-revision N`, plus scope/id.
|
|
45
|
+
Use confirmed only for a preference supported by the user's instruction. If uncertain
|
|
46
|
+
about cross-project scope, save a suggestion rather than generalizing one correction.
|
|
47
|
+
|
|
48
|
+
## Weekly proposals
|
|
49
|
+
|
|
50
|
+
The owner enables analysis per brand in the web app, with explicit consent to send
|
|
51
|
+
saved feedback and confirmed brand preferences to Google Gemini. Videos are not sent.
|
|
52
|
+
The analysis considers at most 50 notes from the last seven days; reports expose coverage,
|
|
53
|
+
supporting feedback and usage. No fine-tuning, cross-customer learning or automatic editing.
|
|
54
|
+
Manual review is limited to once per day; scheduled reviews run weekly. Fewer than two
|
|
55
|
+
notes returns insufficient data. Two notes are not proof a preference generalizes.
|
|
56
|
+
|
|
57
|
+
Use `get_improvement_reviews({brandId})` / `improvements list --brand ID` only when relevant.
|
|
58
|
+
`accept_improvement({runId,index,expectedRevision})` / `improvements accept RUN --index N --expected-revision N`
|
|
59
|
+
requires user acceptance of that suggestion. Changed brand memory invalidates an old
|
|
60
|
+
review; do not bypass that conflict or silently apply it elsewhere. Acceptance changes
|
|
61
|
+
future context, not already rendered videos. Disabling weekly analysis stops future calls,
|
|
62
|
+
not a provider request already in flight. It does not erase past proposals.
|
|
63
|
+
|
|
64
|
+
## Document history
|
|
65
|
+
|
|
66
|
+
`list_document_versions({path,before?})` / `documents history PATH [--before N]` returns
|
|
67
|
+
50 revisions and a cursor. Read an old version with `read_document({path,revision})` /
|
|
68
|
+
`documents get PATH --revision N`. Compare it with current content before restoring.
|
|
69
|
+
`restore_document_version({path,revision,expectedRevision})` / `documents restore PATH --revision N --expected-revision N`
|
|
70
|
+
creates a NEW revision containing that historical content; nothing is deleted.
|
|
71
|
+
After restoring remotely, refresh local files with conflict-aware pull.
|
|
72
|
+
History covers synced documents, not arbitrary local files or complete video timelines.
|
|
73
|
+
|
|
74
|
+
## Share only a specifically authorized artifact
|
|
75
|
+
|
|
76
|
+
Use own uploaded production media already linked in `videos/<project>/media.json`.
|
|
77
|
+
Do not republish library reference footage. PNG/JPEG/WebP and MP4/WebM are supported.
|
|
78
|
+
`create_review_link({projectId,assetId,title,kind:'sample'|'render',days:1..30,shareAuthorized:true,context?})`
|
|
79
|
+
creates a bearer link: anyone possessing it can view the exact asset. CLI:
|
|
80
|
+
`review create --project ID --asset SHA --title TEXT --kind sample --days 7 --share-authorized`.
|
|
81
|
+
Creation does not email or message anyone. Ask only if authorization to share is missing.
|
|
82
|
+
Do not store the secret URL in portable files, logs or source control. Return it only
|
|
83
|
+
to the user requesting it. It is returned once; list endpoints never reveal tokens.
|
|
84
|
+
|
|
85
|
+
Optional `context` maps document paths to `{revision,sha256}` verified by the server.
|
|
86
|
+
These pins are an agent declaration, not proof that the render used that configuration.
|
|
87
|
+
Without pins, the server labels context not recorded. The asset hash always fixes the file.
|
|
88
|
+
Up to 100 active links per workspace. Read with `list_review_links({projectId})` /
|
|
89
|
+
`review list --project ID`; revoke with `revoke_review_link({id})` / `review revoke ID`.
|
|
90
|
+
Expiry/revocation prevents subsequent access; it cannot recall an already downloaded copy.
|
|
91
|
+
The viewer does not certify quality or provide timestamp comments/approval in this version.
|
|
@@ -18,20 +18,23 @@ CLAUDE.md Claude Code entry point (existing instructions
|
|
|
18
18
|
tokens.json Exact color/font/other named values and strengths
|
|
19
19
|
language.json Language, glossary, pronunciations
|
|
20
20
|
assets.json Brand asset declarations
|
|
21
|
+
preferences.json Optional scoped editorial memory
|
|
21
22
|
styles/<style-id>/
|
|
22
23
|
style.md Editorial method and intended effect
|
|
23
24
|
style.json Style tokens, reference IDs, component status
|
|
24
25
|
effects.md Motion and effect guidance (optional)
|
|
25
26
|
music.md Music, voice and sound guidance (optional)
|
|
26
27
|
examples.json Saved reference examples
|
|
28
|
+
preferences.json Optional scoped editorial memory
|
|
27
29
|
output-profiles/<profile-id>.json Dimensions, fps, captions, safe areas
|
|
28
30
|
library/index.json Local reference index, not the entire remote library
|
|
29
|
-
memory/preferences.json
|
|
31
|
+
memory/preferences.json Legacy notes, preserved; not auto-applied
|
|
30
32
|
videos/<project-id>/
|
|
31
33
|
project.json Brand/style/profile IDs, intent, script, overrides
|
|
32
34
|
brief.md Goal, audience, constraints, material
|
|
33
35
|
direction.md Decisions for this specific edit
|
|
34
36
|
media.json Production asset metadata (optional)
|
|
37
|
+
preferences.json Optional project-specific memory
|
|
35
38
|
assets/ Local production media
|
|
36
39
|
plans/ Local plans and implementation notes
|
|
37
40
|
search-brief.json Agent analysis for retrieval (local, not auto-synced)
|
|
@@ -41,7 +44,7 @@ videos/<project-id>/
|
|
|
41
44
|
|
|
42
45
|
The native skill folders are local instructions, not portable documents synchronized by `push`. Local media/render folders are not media uploads. `.editorbrain/.sync.json` is CLI-managed sync state; do not edit it to bypass conflicts. An older valid workspace may omit the optional files and local production directories.
|
|
43
46
|
|
|
44
|
-
The resolver requires the selected brand's `brand.md`, `tokens.json`, `language.json`, `assets.json`; the selected style's `style.md`, `style.json`, `examples.json`; the selected output profile; and the project's `project.json`, `brief.md`, `direction.md`. Preserve them even when a declaration is empty. Additional guidance such as `adaptation-rules.json`, library indexes or memory may be present: read it explicitly when relevant. It is not automatically included in `resolve` merely because it exists.
|
|
47
|
+
The resolver requires the selected brand's `brand.md`, `tokens.json`, `language.json`, `assets.json`; the selected style's `style.md`, `style.json`, `examples.json`; the selected output profile; and the project's `project.json`, `brief.md`, `direction.md`. Preserve them even when a declaration is empty. Scoped `preferences.json` files are optional resolver inputs with pinned hashes; only confirmed entries are returned as active memory. Additional guidance such as `adaptation-rules.json`, library indexes or legacy memory may be present: read it explicitly when relevant. It is not automatically included in `resolve` merely because it exists.
|
|
45
48
|
|
|
46
49
|
## Brand, style and project exceptions
|
|
47
50
|
|
|
@@ -90,3 +93,5 @@ explicit user instruction takes precedence. Read the effective value with
|
|
|
90
93
|
`check_workflow` / `editorbrain workflow check`; local files alone cannot reveal a
|
|
91
94
|
new web preference. Store received versions and scoped approvals in `direction.md`.
|
|
92
95
|
Brand colors/fonts and editing effects/music remain in their existing files.
|
|
96
|
+
|
|
97
|
+
See [memory and review](memory-and-review.md) for memory schemas, version restoration, saved feedback and sharing. Legacy unscoped notes are preserved but are not silently assigned to every brand.
|