diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..bf70b9d --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @is2b007 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..970a2e9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,80 @@ +name: Bug report +description: Report reproducible behavior that is wrong or unsafe +title: "[Bug]: " +labels: + - bug +body: + - type: markdown + attributes: + value: | + Thank you for helping improve Reed. Use a disposable project where possible and remove story text, tokens, repository capabilities, and connector URLs from screenshots and logs. + - type: dropdown + id: platform + attributes: + label: Platform + options: + - macOS Apple silicon + - Android / Daylight DC-1 + - Android / another device + - CLI + - Local MCP + - Remote Agent Access / relay + - Export / Unity integration + validations: + required: true + - type: input + id: version + attributes: + label: Reed version or commit + placeholder: v0.1.2 or commit SHA + validations: + required: true + - type: textarea + id: problem + attributes: + label: What happened? + description: Describe the observed behavior and its effect on your work. + validations: + required: true + - type: textarea + id: steps + attributes: + label: Steps to reproduce + placeholder: | + 1. Create a disposable project... + 2. Open... + 3. Select... + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected behavior + validations: + required: true + - type: dropdown + id: network + attributes: + label: Network state + options: + - Offline + - Online, GitHub disabled + - Online, GitHub enabled + - Remote Agent Access active + - Not relevant + validations: + required: true + - type: textarea + id: evidence + attributes: + label: Sanitized evidence + description: Add screenshots or logs only after removing private story content, tokens, paths, and connector URLs. + - type: checkboxes + id: safety + attributes: + label: Safety check + options: + - label: I have not included a GitHub token, connector capability, private repository URL, database, or private story content. + required: true + - label: This is not a security vulnerability. I will use private vulnerability reporting for security-sensitive issues. + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..312b30d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Security vulnerability + url: https://github.com/is2b007/Reed/security/advisories/new + about: Report vulnerabilities and credential/data exposure privately. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..936fa60 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,53 @@ +name: Feature request +description: Propose a bounded improvement to Reed's authoring workflow +title: "[Feature]: " +labels: + - enhancement +body: + - type: textarea + id: workflow + attributes: + label: Authoring problem + description: What job is difficult today, and who is doing it? + validations: + required: true + - type: textarea + id: proposal + attributes: + label: Proposed behavior + description: Describe the smallest useful outcome, not only an implementation. + validations: + required: true + - type: dropdown + id: platform + attributes: + label: Primary surface + options: + - macOS editor + - Android / Daylight DC-1 + - Both editors + - CLI + - MCP / external agents + - Pixel Crushers / Unity export + - Voice production + - Git / GitHub collaboration + validations: + required: true + - type: textarea + id: offline + attributes: + label: Offline behavior + description: Explain how this remains useful without a network and whether it proposes any new network boundary. + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + - type: checkboxes + id: boundaries + attributes: + label: Product boundaries + options: + - label: The proposal does not require a Reed account, telemetry, cloud project storage, remote assets, or an embedded LLM. + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..9cb6c72 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ +## What changed + +Describe the user-visible change and why Reed needs it. + +## Offline and data-safety impact + +- Does opening Reed or an idle workspace start any network process? +- Does this touch SQLite, migrations, permanent IDs, backups, Git credentials, or Remote Agent Access? +- What happens when the network is unavailable? + +## Validation + +- [ ] Type checking passed. +- [ ] Targeted tests passed. +- [ ] Full serial Vitest suite passed. +- [ ] Offline smoke test passed, or this change cannot affect a runtime boundary. +- [ ] Android unit/lint/build checks passed, or Android is unaffected. +- [ ] Visual changes include screenshots made with disposable/demo data. +- [ ] English, Greek, Griko, Italian, and German content remains intact where relevant. +- [ ] Documentation is updated. + +List the exact commands and any checks you could not run. + +## Screenshots or recordings + +Add before/after evidence for interface changes. Do not include private projects, repository capabilities, tokens, or connector URLs. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7f891b2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + typescript: + name: TypeScript, tests, and offline contract + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v7 + - uses: pnpm/action-setup@v6 + with: + version: 11.8.0 + - uses: actions/setup-node@v7 + with: + node-version: 22.22.0 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm typecheck + - run: pnpm build:runtime + - name: Run test files serially + run: pnpm exec vitest run --no-file-parallelism --maxWorkers=1 + - run: pnpm test:offline + + android: + name: Android unit, lint, and APK build + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-java@v5 + with: + distribution: temurin + java-version: "21" + - uses: android-actions/setup-android@v4 + - name: Install Android SDK 36 + run: sdkmanager "platforms;android-36" "build-tools;36.0.0" + - name: Test, lint, and assemble + working-directory: apps/android + run: ./gradlew testDebugUnitTest lintDebug assembleDebug diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..787e016 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,106 @@ +# Reed architecture + +Reed is an offline-first authoring system with two application shells and one shared project contract. The macOS implementation is TypeScript/Electron; Android is Kotlin/Compose. Both keep SQLite in WAL mode as the canonical store and preserve the same permanent IDs, versioned mutations, production guardrails, and deterministic export semantics. + +## System view + +```mermaid +flowchart TB + subgraph Desktop["macOS"] + Editor["Electron + React editor"] + CLI["Local CLI"] + MCP["Local stdio MCP"] + TSCore["@reed/core"] + Editor --> TSCore + CLI --> TSCore + MCP --> TSCore + end + + subgraph Tablet["Android / Daylight DC-1"] + Compose["Kotlin + Compose editor"] + AgentService["Optional foreground agent service"] + AndroidCore["com.reed.core.ReedCore"] + Compose --> AndroidCore + AgentService --> AndroidCore + end + + TSCore --> DesktopDB["SQLite + WAL"] + AndroidCore --> AndroidDB["SQLite + WAL"] + TSCore --> DesktopExports["Deterministic local exports"] + AndroidCore --> AndroidExports["Deterministic local exports"] + + Editor -. "explicit Git action" .-> DesktopGit["git + gh"] + Compose -. "explicit Git action" .-> JGit["JGit + Android Keystore"] + Claude["External agent"] -. "expiring connector" .-> Relay["Memory-only relay"] + Relay -. "HTTPS long poll" .-> AgentService +``` + +Solid lines are local calls. Dotted lines are optional network boundaries that require an explicit user action. + +## Sources of truth + +- A project's SQLite database is canonical. +- SQLite uses WAL mode for crash resilience and concurrent local readers. +- `exports/reed-project.json` is deterministic, reviewable output, not a second database. +- Unity/Pixel Crushers JSON is generated output and never imported back as canonical state. +- Line IDs and Pixel Crushers numeric mappings are permanent once allocated. +- Every mutation increments the project version and records history. +- Mutations accept `expectedVersion` where stale writes could overwrite newer work. + +## Desktop implementation + +`apps/editor` contains the Electron shell and React interface. The renderer has no raw filesystem, SQL, Git, or network authority; privileged operations cross the typed preload/IPC boundary and are implemented by the main process through `@reed/core`. + +`packages/core` owns the TypeScript domain model, SQLite migrations, validation, history, backups, production rules, Git orchestration, and export generation. `packages/cli` and `apps/mcp` are thin clients over that core. + +Desktop GitHub operations invoke bundled or system `git` and `gh`. GitHub CLI owns authentication through the operating-system credential store. Reed does not copy tokens into project files, preferences, SQLite, logs, or Git configuration. + +## Android implementation + +`apps/android/app` contains the Compose application, responsive workspace, input handling, and foreground agent service. `apps/android/core` is the Android implementation of the Reed snapshot and mutation contracts. It owns Room/SQLite access and platform-parity tests. + +Android cannot rely on child-process Git, so `apps/android/git` uses JGit. A repository token is optional, encrypted through Android Keystore, and supplied to JGit only for the operation the user requested. + +`apps/android/remote` implements the narrow Remote Agent Access transport. It is disabled by default, scoped to one open project, expires within 24 hours, and runs only as an Android foreground service with a persistent Disconnect action. + +## Remote Agent Access boundary + +The relay in `apps/relay` coordinates one tablet channel in process memory. It does not have a Reed account system, database, object store, durable queue, analytics pipeline, or LLM client. Restarting it drops active channels. + +Remote tools may call guarded ReedCore operations. They cannot access Git, raw SQL, arbitrary files, shell execution, or credentials. Agents cannot promote text beyond `Polished`, mutate Final content, or bypass version conflicts and exact destructive confirmations. + +See [Remote MCP from Claude Android](docs/REMOTE_MCP_ANDROID.md) for the deployment and threat model. + +## Mutation and production invariants + +- Final content is controlled by a person. +- Editing text with recorded-or-later voice status changes voice status to `Rework`. +- Destructive actions require confirmation or a reversible undo path. +- Agent mutations are recorded with an agent source and remain reviewable. +- English, Greek, Griko, Italian, and German remain valid UTF-8 across storage, UI, MCP, CLI, and exports. +- Node type, status, validation, and speaker identity are never communicated by color alone. + +## Repository map + +| Path | Responsibility | +|---|---| +| `apps/editor` | Electron main process, preload boundary, React UI, macOS packaging | +| `apps/android/app` | Compose UI, adaptive input, foreground remote-agent service | +| `apps/android/core` | Android SQLite model and mutation parity | +| `apps/android/git` | JGit transport and Keystore-backed credential handling | +| `apps/android/remote` | Relay protocol and connector capability storage | +| `apps/mcp` | Local stdio MCP entrypoint | +| `apps/relay` | Optional single-process, memory-only remote MCP relay | +| `packages/core` | TypeScript canonical domain, persistence, Git, backups, exports | +| `packages/schema` | Shared TypeScript contracts and schemas | +| `packages/cli` | Local command-line interface | + +## Verification layers + +1. TypeScript type checking for every workspace package. +2. Unit and regression tests for core, editor logic, Git/GitHub orchestration, relay behavior, and concurrency. +3. Android unit tests and parity tests, plus lint and APK assembly. +4. An offline smoke test covering core, CLI, MCP, backups, Git-disabled operation, Unicode exports, and the editor network boundary. +5. Manual DC-1 checks for touch, keyboard, mouse, trackpad, pen hover, background agent access, and lifecycle behavior. + +Read [CONTRIBUTING.md](CONTRIBUTING.md) before changing a platform boundary. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..40fbbf0 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our pledge + +We as members, contributors, and leaders pledge to make participation in the Reed community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our standards + +Examples of behavior that contributes to a positive environment include: + +- demonstrating empathy and kindness toward other people; +- respecting differing opinions, viewpoints, and experiences; +- giving and gracefully accepting constructive feedback; +- accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience; +- focusing on what is best not just for us as individuals, but for the overall community. + +Examples of unacceptable behavior include: + +- the use of sexualized language or imagery, and sexual attention or advances of any kind; +- trolling, insulting or derogatory comments, and personal or political attacks; +- public or private harassment; +- publishing others' private information, such as a physical or email address, without explicit permission; and +- other conduct which could reasonably be considered inappropriate in a professional setting. + +## Enforcement responsibilities + +Project maintainers are responsible for clarifying and enforcing these standards and will take appropriate and fair corrective action in response to behavior they consider inappropriate, threatening, offensive, or harmful. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that do not align with this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces and when an individual officially represents the community in public spaces. + +## Enforcement + +Report abusive, harassing, or otherwise unacceptable behavior privately through a contact method on the [maintainer's GitHub profile](https://github.com/is2b007). Do not place sensitive personal information in a public issue. Security vulnerabilities should use [private vulnerability reporting](https://github.com/is2b007/Reed/security/advisories/new). + +All reports will be reviewed and investigated promptly and fairly. Maintainers must respect the privacy and security of the reporter. + +## Enforcement guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for actions they deem in violation of this Code of Conduct. + +### 1. Correction + +**Community impact:** Use of inappropriate language or other behavior deemed unprofessional or unwelcome. + +**Consequence:** A private, written warning providing clarity around the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community impact:** A violation through a single incident or series of actions. + +**Consequence:** A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary ban + +**Community impact:** A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence:** A temporary ban from interaction or public communication with the community. Violating these terms may lead to a permanent ban. + +### 4. Permanent ban + +**Community impact:** A pattern of violating community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence:** A permanent ban from public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html), available under the [Creative Commons Attribution 4.0 License](https://creativecommons.org/licenses/by/4.0/). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5379b16 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,141 @@ +# Contributing to Reed + +Thank you for helping build Reed. This project values small, reviewable changes that preserve authors' local data and keep the application fully useful offline. + +## Before you start + +Read: + +1. [AGENTS.md](AGENTS.md) for non-negotiable implementation rules; +2. [DESIGN.md](DESIGN.md) before changing interface behavior or appearance; +3. [ARCHITECTURE.md](ARCHITECTURE.md) before changing persistence, networking, Git, MCP, or platform boundaries; and +4. [the offline contract](docs/OFFLINE_CONTRACT.md) before adding any runtime dependency or entrypoint. + +Please use an issue before starting a large feature, a data migration, a new network boundary, or a change to permanent IDs/export compatibility. Small bug fixes with a clear regression test can go directly to a pull request. + +## Development setup + +Required for the shared TypeScript workspace: + +- Node.js `>=22.22.0` +- pnpm `11.8.0` +- Git + +```sh +git clone https://github.com/is2b007/Reed.git +cd Reed +corepack enable +pnpm install --frozen-lockfile +``` + +Run the baseline checks: + +```sh +pnpm typecheck +pnpm exec vitest run --no-file-parallelism --maxWorkers=1 +pnpm test:offline +``` + +The serial Vitest command is the reliable full-suite form because the SQLite and local-Git fixtures can contend for CPU and filesystem time when every test file runs concurrently. + +## macOS editor + +The desktop application currently targets Apple silicon. + +```sh +pnpm --filter @reed/editor start +``` + +Package a locally signed development app: + +```sh +CI=true pnpm --filter @reed/editor package +``` + +The bundle is written to `apps/editor/out/Reed-darwin-arm64/Reed.app`. Apple distribution signing and notarization require maintainer credentials and are not part of contributor CI. + +### Safe product screenshots + +Build the runtime, generate a disposable project, and use Reed's hidden screenshot mode. Never capture private production data for repository documentation. + +```sh +pnpm build:runtime +node scripts/create-demo.mjs /tmp/reed-demo + +Reed.app/Contents/MacOS/Reed \ + --project /tmp/reed-demo \ + --screenshot /tmp/reed-graph.png \ + --screenshot-workspace graph \ + --screenshot-width 1500 \ + --screenshot-height 940 +``` + +## Android editor + +Android development requires JDK 21 and Android SDK API 36. + +```sh +export JAVA_HOME=/path/to/jdk-21 +pnpm android:test +pnpm android:lint +pnpm android:build +``` + +Install without clearing the current application data: + +```sh +adb install -r apps/android/app/build/outputs/apk/debug/app-debug.apk +``` + +### Protect real tablet data + +Do not run `connectedDebugAndroidTest` on a DC-1 or another device that contains the only copy of a Reed project. Android's connected-test lifecycle can replace the debug package and clear its local application data. Reed blocks connected tests unless the command explicitly includes `-PallowDeviceDataReset=true`; use that flag only on a disposable device/profile or after verifying a backup. + +Test tablet UI changes in portrait, landscape, split screen, and a compact window. Check touch, keyboard, mouse, trackpad, pen hover, the Wacom side button, reduced motion, and grayscale contrast where relevant. + +## Change rules + +- Route all reads and writes through the platform ReedCore implementation. +- Do not write raw SQL or canonical JSON from a client. +- Add a migration for persisted model changes and preserve older projects. +- Never recycle Line IDs or Pixel Crushers numeric mappings. +- Preserve optimistic concurrency and mutation history. +- Do not add a background fetch, telemetry call, updater, remote asset, hosted configuration, Reed account, or embedded LLM. +- Keep Git/GitHub optional, per-project, and user-triggered. +- Keep Remote Agent Access off by default, expiring, foreground-visible, and limited to guarded Reed tools. +- Add or update an automated offline test for every runtime entrypoint. +- Pair color with text, shape, icon, border, or pattern. +- Verify English, Greek, Griko, Italian, and German strings remain intact. + +## Tests by change type + +| Change | Minimum validation | +|---|---| +| Shared schema/core | `pnpm typecheck`, targeted tests, full serial Vitest suite, offline smoke | +| Electron UI/main process | Typecheck, targeted regression test, full serial Vitest suite | +| Export | Core tests, deterministic byte comparison, Unicode case, offline smoke | +| Git/GitHub | Local Git fixture tests; no live user repository in automated tests | +| MCP/CLI | Tool/command tests plus offline smoke | +| Relay | Relay integration tests with ephemeral localhost sockets and no persisted bodies | +| Android | `testDebugUnitTest`, `lintDebug`, `assembleDebug`; device check when interaction changes | +| Network boundary | Offline smoke plus a test proving idle/open behavior starts no network process | + +## Pull requests + +1. Create a focused branch from `main`. +2. Keep unrelated changes out of the commit. +3. Explain the user-visible problem and the chosen boundary. +4. Add a regression test for a bug or contract test for new behavior. +5. Include real screenshots for visual changes, using only demo data. +6. Report exact validation commands and any checks you could not run. +7. Call out migrations, compatibility changes, new permissions, and any network effect. + +Commit messages should be short and descriptive, for example: + +```text +fix(android): preserve pinch focal point +feat(core): export per-actor recording packets +docs: explain remote agent security boundary +``` + +By participating, you agree to follow the [Code of Conduct](CODE_OF_CONDUCT.md). Report vulnerabilities privately as described in [SECURITY.md](SECURITY.md). diff --git a/README.md b/README.md index dca5ef9..4109f46 100644 --- a/README.md +++ b/README.md @@ -1,124 +1,246 @@ # Reed -Reed is an offline-first branching-dialogue workstation for Unity projects using Pixel Crushers Dialogue System. It combines a visual Electron editor for macOS, a native Android tablet editor, a local stdio MCP server for external agents, a scriptable CLI, and platform SQLite/WAL core implementations that share one deterministic project contract. +

+ Reed app icon +

-The application is fully useful without a network connection and has no Reed account, telemetry, updater, cloud project storage, remote asset, or embedded LLM client. An external agent may contact its own configured model endpoint, then call Reed locally through MCP or the CLI. Optional GitHub collaboration is disabled per project until a user turns it on; even then, Reed connects only when the user presses a GitHub action. Android also has explicit, expiring Remote Agent Access for Claude mobile through a separately deployed transient relay. +

+ An offline-first branching dialogue workstation for Unity and Pixel Crushers.
+ Write, localize, review, playtest, version, and export a story from macOS or an Android tablet. +

-## What is included +

+ CI status + macOS Apple silicon + Android 13 and newer + Node 22 + Offline first +

-- Dense React Flow graph editing with line, choice, group, and cross-conversation links; any two configured languages side by side; per-line spoken-language selection; permanent Line IDs; protected Final content; and text-only playtest. -- Native Mac menus, persisted Dark/Light/Automatic appearance, an in-app project home with recent local projects, versioned project settings, project navigator, beat map, cast and variable registries, global local search, translation coverage, validation dashboard, review snapshots, read view, voice budget, and hot reload of CLI/MCP mutations. -- SQLite WAL storage, migrations, optimistic concurrency, append-only mutation history, autosave with a visible save state, rolling and named backups, exact-confirmation restore/delete operations, and deterministic project JSON. -- Optional offline Git checkpoints and local story branches for team review. Pressing **Saved** opens the local-history and GitHub sync center for setup, connection status, repository connection, fetch, and push; the full opt-in GitHub workspace adds repository creation, branches, pull-request creation, review, and merge—without requiring Terminal. Reed stores no GitHub token and performs no background synchronization. -- Pixel Crushers single- or multi-database JSON with stable actor, variable, conversation, and entry IDs; persisted Base ID ranges; localized fields; cross-database links; canvas positions; Lua/Sequence fields; and Line-ID audio manifest. -- Unicode actor PDF, editable studio CSV/XLSX, screenplay Markdown, and word/minute budget exports for English, Greek, Italian, German, and Griko. -- MCP tools and CLI commands backed exclusively by `@reed/core`, with agent status limits and stale-write protection. -- A native Kotlin/Compose Android workspace for the Daylight DC-1 with a grayscale-safe adaptive layout, hardware keyboard/mouse/trackpad controls, Android 13 compatibility, and explicit HTTPS Git clone/checkpoint/fetch/pull/push backed by Android Keystore. -- An opt-in Android foreground MCP bridge for Claude mobile, with a persistent Disconnect notification, encrypted connector capability, guarded ReedCore tools, no Git exposure, and an in-memory self-hostable relay. +![Abstract Reed branching-dialogue graph](docs/assets/reed-hero-background.png) -## Install and verify +Reed is built for narrative teams working on branching, multilingual dialogue. SQLite is the source of truth; the graph, production metadata, history, backups, agent tools, and exports remain available with no network connection. There is no Reed account, telemetry, cloud project store, hosted feature flag, updater, or embedded LLM. -Reed currently targets Node 22+ and pnpm 11. Dependency installation is the development/build step that may use a network. Once built, the app, data, backups, MCP, CLI, and exports run offline. GitHub features remain optional and require a connection only for the action the user requests. +Optional Git and GitHub collaboration is disabled per project until the author enables it. Android's Remote Agent Access is a separate, explicit, expiring session that exposes only guarded Reed tools to an external agent. -### Download the Mac app +> [!IMPORTANT] +> Reed is pre-1.0 software. Keep project backups and verify Pixel Crushers output against the Unity/plugin versions used by your production before shipping a game. -Download the latest Apple-silicon DMG from the [Reed releases page](https://github.com/is2b007/Reed/releases/latest), open it, and drag **Reed** into Applications. Reed is locally signed but not yet Apple-notarized. If macOS says it cannot verify Reed, close the alert, then Control-click **Reed.app** in Applications, choose **Open**, and confirm **Open** once. After that, Reed opens normally. +## See Reed -The GitHub repository is the source-code project. The DMG and ZIP on the releases page are the installable app; opening the repository page itself will not launch Reed. + + + + + +
+ Reed graph workspace on macOS with a multilingual branching conversation +
Graph authoring
+ Dense node editing, character accents, permanent Line IDs, variables, validation, and a contextual inspector. +
+ Reed translation coverage workspace showing English, Greek, Italian, and German dialogue +
Translation coverage
+ English, Greek, Italian, German, and Griko remain visible as authored text, not flattened export data. +
-```sh -pnpm install -CI=true pnpm typecheck -CI=true pnpm test -CI=true pnpm test:offline -``` +The screenshots use the disposable demo project created by [`scripts/create-demo.mjs`](scripts/create-demo.mjs). They contain no private production data. -Build the reusable runtime packages: +## What Reed includes -```sh -CI=true pnpm build:runtime -``` +- A visual graph for line, choice, junction, and cross-conversation flow, with direct connector dragging and create-on-drop. +- Permanent Line IDs, stable Pixel Crushers numeric mappings, conditions, Lua, sequences, tags, variables, cast metadata, and voice context. +- Side-by-side languages, translation coverage, local validation, read view, text-only playtest, beat map, review snapshots, and search. +- Autosave with a visible state, SQLite/WAL history, rolling and named backups, deterministic JSON, and reversible or confirmed destructive actions. +- Voice-actor PDFs, studio XLSX/CSV, screenplay Markdown, word/minute budgets, audio manifests, and Pixel Crushers JSON. +- Optional local Git checkpoints, branches, GitHub sync, and pull-request review from inside Reed. +- A local stdio MCP server and CLI backed by the same versioned core contracts as the editor. + +## macOS and Android + +Reed has two native application shells over equivalent project rules. + +| | macOS | Android / Daylight DC-1 | +|---|---|---| +| Interface | Electron, React, and React Flow | Kotlin and Jetpack Compose | +| Current target | Apple silicon | Android 13+; tested on Daylight DC-1 | +| Storage | `@reed/core`, SQLite in WAL mode | Android `ReedCore`, SQLite in WAL mode | +| Input | Keyboard, mouse, and trackpad | Touch, hardware keyboard, mouse, trackpad, and Wacom EMR pen | +| Canvas | Marquee select, live node drag, connector drop-to-create, trackpad pan, focal zoom | Responsive panes, pen hover, side-button marquee, connector drag, two-finger pan, focal pinch zoom | +| Git | Bundled/system `git` and GitHub CLI credential store | Embedded JGit and optional Android Keystore token | +| External agents | Local stdio MCP or CLI | Explicit foreground Remote Agent Access session | +| Offline default | Yes | Yes | -Build the local macOS application bundle: +### macOS + +Download the latest Apple-silicon build from [GitHub Releases](https://github.com/is2b007/Reed/releases/latest), or build from source below. Published binary releases currently trail the active source tree, so contributors testing the newest Android, GitHub, and remote-agent work should build from `main`. + +The current development app is locally signed but not Apple-notarized. If macOS blocks it, Control-click **Reed.app**, choose **Open**, and confirm once. Intel macOS, Windows, and Linux packages are not currently produced. + +Build a local application bundle: ```sh +pnpm install --frozen-lockfile +CI=true pnpm typecheck +CI=true pnpm exec vitest run --no-file-parallelism --maxWorkers=1 +CI=true pnpm test:offline CI=true pnpm --filter @reed/editor package ``` -The locally signed development app is written to `apps/editor/out/Reed-darwin-arm64/Reed.app`. The Mac package bundles the GitHub CLI when it is available on the build machine, so users do not need to install or run command-line tools. Apple Developer signing and notarization require the distributor's certificate and credentials. +The application is written to `apps/editor/out/Reed-darwin-arm64/Reed.app`. -Build the Android debug APK after installing Android SDK API 36 and accepting Google's Android SDK license terms: +### Android and Daylight DC-1 + +The Android application is optimized for the DC-1's compact grayscale display without becoming device-specific. It supports rotation and split screen, collapsible navigator and inspector panes, keyboard focus, mouse hover, two-finger trackpad pan, pinch zoom around the finger midpoint, pen hover, barrel-button marquee selection, and direct output-port linking. + +Build with JDK 21 and Android SDK API 36: ```sh +export JAVA_HOME=/path/to/jdk-21 pnpm android:test pnpm android:lint pnpm android:build +adb install -r apps/android/app/build/outputs/apk/debug/app-debug.apk ``` -The APK is written to `apps/android/app/build/outputs/apk/debug/app-debug.apk`; the current verified DC-1 debug build is also available locally at `dist/Reed-Android-DC1-debug.apk`. See [Android and Daylight DC-1 setup](docs/ANDROID_DC1.md) for install, input, pen hover, offline, Git, checksum, and device-verification instructions. +`adb install -r` preserves existing app data. Do not run connected Android tests on a device that contains the only copy of a project; Reed requires an explicit `-PallowDeviceDataReset=true` opt-in because Android's connected-test lifecycle can replace the package and clear local data. -## Start using Reed +Read [Android and Daylight DC-1 setup](docs/ANDROID_DC1.md) and the [Android architecture and parity contract](docs/ANDROID_ARCHITECTURE.md). -Create a project from the desktop welcome screen, or create one from the CLI: +## Offline by design -```sh -CI=true pnpm reed init ./my-story --name "My Story" --slug my-story --languages en,el,it,de,griko --default-language en -CI=true pnpm reed --project ./my-story add-scene "Opening" --slug opening -CI=true pnpm reed --project ./my-story --help +```mermaid +flowchart LR + UI["macOS or Android editor"] --> Core["Reed Core contracts"] + CLI["Local CLI"] --> Core + MCP["Local stdio MCP"] --> Core + Core --> DB["SQLite + WAL"] + Core --> Export["Deterministic exports"] + Core --> Backup["Local backups"] + Core -. "explicit action only" .-> Git["Optional Git / GitHub"] + Agent["External agent + its own LLM"] --> MCP ``` -The spec-compatible `dialogue` prefix is accepted too: +Opening Reed, opening a project, editing, saving, validating, backing up, and exporting do not start a network process. The two narrow exceptions are: + +1. a labelled Git/GitHub action after collaboration is enabled for that project; and +2. an explicit Android Remote Agent Access session, scoped to one project and limited to 24 hours or less. + +See the testable [offline contract](docs/OFFLINE_CONTRACT.md). + +## Quick start from source + +Requirements: + +- Node.js `>=22.22.0` +- pnpm `11.8.0` +- JDK 21 and Android SDK API 36 only if building Android +- macOS on Apple silicon only if packaging the desktop app ```sh -CI=true pnpm reed --project ./my-story dialogue validate +git clone https://github.com/is2b007/Reed.git +cd Reed +corepack enable +pnpm install --frozen-lockfile +pnpm typecheck +pnpm exec vitest run --no-file-parallelism --maxWorkers=1 +pnpm test:offline ``` -For the MCP server, build the runtime packages and configure the external agent to start: +Create a project from Reed's welcome screen, or use the CLI: ```sh -node /absolute/path/to/Reed/apps/mcp/dist/index.js --project /absolute/path/to/my-story +pnpm reed init ./my-story \ + --name "My Story" \ + --slug my-story \ + --languages en,el,it,de,griko \ + --default-language en + +pnpm reed --project ./my-story add-scene "Opening" --slug opening +pnpm reed --project ./my-story --help ``` -Transport is stdio only. Reed does not listen on a port. - -## Source of truth and local files +## Project files and Unity export -SQLite is canonical. A project folder contains: +SQLite is canonical. A Reed project contains: ```text my-story/ .reed/ reed.sqlite canonical database - reed.sqlite-wal SQLite write-ahead log while open + reed.sqlite-wal write-ahead log while open backups/ rolling and named SQLite snapshots exports/ reed-project.json deterministic Git-readable snapshot pixel-crushers/ Unity JSON and audio manifests - voice/ Studio PDF, per-actor PDFs, XLSX tracker, and CSV + voice/ studio and actor handoff files screenplay.md ``` -Unity JSON is one-way generated output and is stamped `GENERATED — DO NOT HAND-EDIT`. Never make Unity's Dialogue Editor a second source of truth; make changes in Reed and export again. +Unity JSON is one-way generated output stamped `GENERATED — DO NOT HAND-EDIT`. Make canonical changes in Reed and export again. The exporter has automated coverage for stable IDs, localized fields, Base ID collision prevention, cross-links, Unicode, and manifests, but still needs a real Unity-authored fixture before any Unity/Pixel Crushers version is called certified. + +Read the [Pixel Crushers compatibility checklist](docs/PIXEL_CRUSHERS.md). + +## MCP and external agents + +Build the runtime packages, then configure an MCP-compatible desktop agent to start Reed over stdio: + +```sh +pnpm build:runtime +node /absolute/path/to/Reed/apps/mcp/dist/index.js \ + --project /absolute/path/to/my-story +``` + +Reed does not contain an LLM client. Agents use their own model connection and reach the same mutation APIs as the CLI and editor. Agent-authored text cannot be promoted above `Polished`; `Final` remains human-controlled. + +On Android, Remote Agent Access is deliberately different: Reed starts a foreground service with a persistent Disconnect notification and creates an expiring connector through a memory-only relay. It exposes no Git, raw SQL, arbitrary files, shell, or LLM client. Read [Remote MCP from Claude Android](docs/REMOTE_MCP_ANDROID.md). + +## Repository map + +```text +apps/ + editor/ macOS Electron application + android/ native Android application and platform core + mcp/ local stdio MCP entrypoint + relay/ optional memory-only Android connector relay +packages/ + core/ canonical TypeScript domain and persistence rules + schema/ shared graph and tool contracts + cli/ local command-line interface +docs/ product, platform, integration, and production guides +scripts/ offline verification, demo, and relay operations +``` + +The platform-level view is in [ARCHITECTURE.md](ARCHITECTURE.md). ## Documentation -- [Data model and graph contract](docs/DATA_MODEL.md) -- [CLI reference](docs/CLI.md) -- [MCP tool reference](docs/MCP.md) -- [MCP setup for humans](docs/MCP_SETUP.md) -- [MCP operating playbook for AI agents](docs/AI_MCP_PLAYBOOK.md) -- [Pixel Crushers export and Unity import](docs/PIXEL_CRUSHERS.md) -- [Local history and optional GitHub collaboration](docs/PROJECT_HISTORY.md) -- [Voice production handoff](docs/VOICE_PRODUCTION.md) -- [Offline contract and release acceptance](docs/OFFLINE_CONTRACT.md) -- [Architecture and completion plan](docs/BUILD_PLAN.md) -- [Editor design rationale](docs/EDITOR_DESIGN.md) -- [Visual research](docs/VISUAL_REFERENCES.md) -- [Product design system](DESIGN.md) -- [Android and Daylight DC-1 setup](docs/ANDROID_DC1.md) -- [Android architecture and parity contract](docs/ANDROID_ARCHITECTURE.md) -- [Remote MCP from Claude Android](docs/REMOTE_MCP_ANDROID.md) - -## Compatibility boundary - -The exporter follows the documented Pixel Crushers DialogueDatabase shape and has deterministic automated coverage for localized fields, stable IDs, Base ID collision prevention, cross-links, Unicode, and manifests. A real Unity-authored Pixel Crushers fixture has not been supplied to this repository, so a Unity import/export round trip and version-specific localized-field mapping must be verified before calling a particular Pixel Crushers/Unity version certified. See the fixture checklist in [docs/PIXEL_CRUSHERS.md](docs/PIXEL_CRUSHERS.md). +| Start here | Purpose | +|---|---| +| [Contributing](CONTRIBUTING.md) | Development setup, test tiers, pull requests, and platform guardrails | +| [Architecture](ARCHITECTURE.md) | Components, sources of truth, and network boundaries | +| [Data model](docs/DATA_MODEL.md) | Project hierarchy, IDs, versions, and graph records | +| [CLI reference](docs/CLI.md) | Scriptable local workflows | +| [MCP reference](docs/MCP.md) | Local agent tool contract | +| [MCP setup](docs/MCP_SETUP.md) | Configuration for humans and AI coding tools | +| [AI MCP playbook](docs/AI_MCP_PLAYBOOK.md) | Safe agent operating sequence | +| [Project history](docs/PROJECT_HISTORY.md) | Backups, local Git, optional GitHub, and pull requests | +| [Voice production](docs/VOICE_PRODUCTION.md) | Actor and studio export workflow | +| [Offline contract](docs/OFFLINE_CONTRACT.md) | Allowed networking and release acceptance | +| [Android / DC-1](docs/ANDROID_DC1.md) | Build, install, input, Git, and device verification | +| [Remote Android MCP](docs/REMOTE_MCP_ANDROID.md) | Claude connector model and relay deployment | +| [Pixel Crushers](docs/PIXEL_CRUSHERS.md) | Export shape, Unity import, and certification boundary | +| [Product brief](docs/PRODUCT_BRIEF.md) | Product goals, users, and scope | +| [Build plan](docs/BUILD_PLAN.md) | Delivery architecture and completion sequence | +| [Editor design](docs/EDITOR_DESIGN.md) | Workspace behavior and interaction rationale | +| [Visual references](docs/VISUAL_REFERENCES.md) | Source research and Reed-specific takeaways | +| [Design system](DESIGN.md) | Reed's industrial-editorial interface rules | + +## Contributing and community + +Contributions are welcome once the repository is made public. Start with [CONTRIBUTING.md](CONTRIBUTING.md), follow the [Code of Conduct](CODE_OF_CONDUCT.md), and use the issue forms for reproducible bugs or bounded proposals. Security-sensitive reports belong in [GitHub's private vulnerability report](https://github.com/is2b007/Reed/security/advisories/new), not a public issue. + +The [open-source launch checklist](docs/OPEN_SOURCE_CHECKLIST.md) records the remaining repository-owner decisions and GitHub settings. + +## License + +No open-source license has been selected yet. Until a `LICENSE` file is added, copyright law applies and the source is not licensed for reuse or redistribution. Choosing a license is the final legal blocker before making this repository public. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..c3d328c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,59 @@ +# Security policy + +Reed protects locally authored story data. Security reports involving project confidentiality, credential handling, offline guarantees, destructive mutations, or Remote Agent Access are treated as product-security issues. + +## Supported versions + +Reed is pre-1.0. Security fixes are made on `main` and included in the next tagged release. Older preview builds may not receive separate patches. + +| Version | Supported | +|---|---| +| `main` / latest source | Yes | +| Latest tagged preview | Best effort | +| Older preview releases | No | + +## Report a vulnerability privately + +Use [GitHub private vulnerability reporting](https://github.com/is2b007/Reed/security/advisories/new). Do not open a public issue for a suspected vulnerability and do not include a real project, GitHub token, connector capability URL, database, or private story content in a report. + +Include, when possible: + +- the affected commit or release; +- macOS/Android version and device architecture; +- whether GitHub collaboration or Remote Agent Access was enabled; +- steps using a disposable project; +- expected and observed behavior; +- security impact; and +- a minimal proof of concept with secrets removed. + +The maintainer will acknowledge reports and coordinate disclosure on a best-effort basis. Please allow time for a fix and release before publishing details. + +## High-priority boundaries + +Please report: + +- network traffic started by opening Reed or an idle workspace; +- story data, SQL, arbitrary files, shell access, Git, or credentials exposed through Android Remote Agent Access; +- connector capabilities, GitHub tokens, request bodies, or story text persisted in relay logs/storage; +- GitHub credentials written to a project, SQLite, preferences, logs, or Git configuration; +- bypasses for Final-content protection, version conflicts, exact destructive confirmation, or voice `Rework` rules; +- path traversal outside an open project; +- unsafe import/export behavior that overwrites unrelated files; +- a relay authorization, request-mixing, replay, or cross-channel isolation failure; or +- a dependency vulnerability that is reachable through Reed's runtime behavior. + +## Designed security boundaries + +- Normal authoring, storage, backup, validation, playtest, and export are local. +- Git/GitHub is optional per project and runs only after a labelled user action. +- Desktop authentication belongs to GitHub CLI and the operating-system credential store. +- Android can encrypt an optional repository token with Android Keystore and supplies it only to JGit for the requested operation. +- Remote Agent Access is off by default, scoped to one project, limited to 24 hours or less, and visible through a foreground notification with Disconnect. +- The relay keeps active channel state in memory only and must redact query strings and authorization headers from infrastructure logs. +- Remote tools cannot invoke Git, SQL, arbitrary files, shell execution, or an LLM. + +The complete acceptance contract is in [docs/OFFLINE_CONTRACT.md](docs/OFFLINE_CONTRACT.md), and the Android relay threat model is in [docs/REMOTE_MCP_ANDROID.md](docs/REMOTE_MCP_ANDROID.md). + +## Public hardening work + +Before the repository becomes public, the owner should enable GitHub private vulnerability reporting, secret scanning, dependency alerts, and branch protection. See [docs/OPEN_SOURCE_CHECKLIST.md](docs/OPEN_SOURCE_CHECKLIST.md). diff --git a/docs/OPEN_SOURCE_CHECKLIST.md b/docs/OPEN_SOURCE_CHECKLIST.md new file mode 100644 index 0000000..dbf649c --- /dev/null +++ b/docs/OPEN_SOURCE_CHECKLIST.md @@ -0,0 +1,60 @@ +# Open-source launch checklist + +This checklist separates repository preparation from the one-way owner decisions required before changing Reed from private to public. + +## Completed in the repository + +- [x] Product-focused README with real demo screenshots. +- [x] macOS and Android/DC-1 build and support boundaries. +- [x] Architecture and offline/network trust-boundary documentation. +- [x] Contributor setup and test tiers. +- [x] Security policy and private reporting path. +- [x] Code of Conduct. +- [x] Bug, feature, and pull-request templates. +- [x] Least-privilege GitHub Actions CI definition. +- [x] Generated visual assets use no production story data. +- [x] Repository description and topics prepared. + +## Owner decisions before public visibility + +- [ ] **Choose an open-source license.** This is the legal blocker. Common options are: + - MIT for short, permissive reuse terms; + - Apache-2.0 for permissive terms with an explicit patent grant; + - MPL-2.0 for file-level copyleft; or + - GPL-3.0 for strong copyleft. +- [ ] Confirm the copyright owner name and year used in `LICENSE`. +- [ ] Decide whether the optional hosted relay is a community reference deployment, maintainer-operated service, or self-host-only component. +- [ ] Decide which maintainers may triage private security and conduct reports. + +Do not change repository visibility until a license is committed. A public repository without a license is visible source, not open source. + +## GitHub settings + +- [ ] Upload `docs/assets/reed-hero-background.png` as the repository social preview. +- [ ] Enable Issues and keep blank issues disabled. +- [ ] Enable Discussions only if someone will actively moderate it. +- [ ] Enable private vulnerability reporting. +- [ ] Enable secret scanning and push protection where the account plan allows it. +- [ ] Enable Dependabot alerts and security updates. +- [ ] Protect `main`: require pull requests, require CI, block force pushes, and require the branch to be current before merge. +- [ ] Configure merge methods; squash or merge commits are both compatible with Reed's project workflow. +- [ ] Review repository Actions permissions and keep the default workflow token read-only unless a workflow explicitly needs more. +- [ ] Add a public contact method for Code of Conduct reports. + +## Release readiness + +- [ ] Publish a current macOS Apple-silicon release; the latest tagged binary currently trails the source version. +- [ ] Decide whether to notarize macOS builds before inviting non-technical users. +- [ ] Publish an Android APK only after release signing, upgrade/install testing, and DC-1 smoke checks. +- [ ] Document checksums for downloadable artifacts. +- [ ] Run `pnpm typecheck`, the full serial Vitest suite, `pnpm test:offline`, and the Android unit/lint/build suite from a clean checkout. +- [ ] Verify a real Unity-authored Pixel Crushers fixture before claiming version certification. +- [ ] Verify that no repository screenshot contains a private path, token, repository, or story. + +## Visibility change + +- [ ] Run a secret-history scan, not only a working-tree scan. +- [ ] Review commit authorship and remove any accidental personal files from Git history. +- [ ] Confirm third-party dependency and bundled-font licenses are compatible with the selected project license and distribution model. +- [ ] Change visibility only after all legal and security blockers above are resolved. +- [ ] Open the public README, screenshots, issue forms, CI, security page, and release downloads in a signed-out browser. diff --git a/docs/assets/reed-hero-background.png b/docs/assets/reed-hero-background.png new file mode 100644 index 0000000..0bfea80 Binary files /dev/null and b/docs/assets/reed-hero-background.png differ diff --git a/docs/assets/reed-macos-graph.png b/docs/assets/reed-macos-graph.png new file mode 100644 index 0000000..f094b35 Binary files /dev/null and b/docs/assets/reed-macos-graph.png differ diff --git a/docs/assets/reed-macos-translation.png b/docs/assets/reed-macos-translation.png new file mode 100644 index 0000000..7c45a02 Binary files /dev/null and b/docs/assets/reed-macos-translation.png differ diff --git a/docs/assets/reed-mark.png b/docs/assets/reed-mark.png new file mode 100644 index 0000000..b89f8c4 Binary files /dev/null and b/docs/assets/reed-mark.png differ diff --git a/package.json b/package.json index 64f2121..d5d2b4f 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,26 @@ { "name": "reed", "version": "0.1.9", + "description": "Offline-first branching dialogue editor for Unity and Pixel Crushers on macOS and Android", "private": true, "type": "module", + "homepage": "https://github.com/is2b007/Reed#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/is2b007/Reed.git" + }, + "bugs": { + "url": "https://github.com/is2b007/Reed/issues" + }, + "keywords": [ + "branching-dialogue", + "unity", + "pixel-crushers", + "narrative-design", + "localization", + "offline-first", + "mcp" + ], "packageManager": "pnpm@11.8.0", "engines": { "node": ">=22.22.0"