Graphical existing-project importer
kronika gui serves an accessible browser workspace from the installed package. It prints the exact session URL and does not open a browser. The workspace adopts existing Markdown through initializeDocumentationWorkspace, the same exported TypeScript function called by kronika init. There is one manifest format and one persistence implementation.
Start the workspace
kronika gui --repo /path/to/project
# Select a fixed loopback port when needed:
kronika gui --repo /path/to/project --port 4173
Open the printed URL exactly, including its token fragment. By default the operating system assigns an available port. The server binds 127.0.0.1 only; it never opens a consent window, model route, deployment, or validation process. Stop the foreground command to end the session.
Fields and established defaults
| GUI field | Adoption option | Blank/default behavior |
|---|---|---|
| Repository | repo | fixed by kronika gui --repo; shown read-only in the workspace |
| Markdown files or directories | documents | existing README.md and docs/; one repository-relative selection per line |
| Evidence files or directories | sources | .; one repository-relative selection per line |
| Manifest path | manifestPath | kronika.sync.json, inside the repository |
| Standing instruction | instruction | Kronika's built-in maintenance instruction |
| Replace conflict | replace | off; a different manifest is preserved and reported |
Browser file controls cannot disclose a real local path, so the local workspace accepts explicit repository-relative selections rather than uploading document copies. The selected files remain at their original paths; directories are traversed by the core importer, duplicate Markdown paths collapse to one identity, source declarations are de-duplicated and sorted, and no document body crosses the HTTP boundary.
Results and readback
The result keeps imported, unchanged, conflicting, and rejected paths separate. Conflicts include the retained manifest path and the reason replacement was refused. Rejections include the source-derived path error. After an imported or unchanged result, the server loads the exact persisted manifest with loadSyncManifest; the workspace renders its schema version and every accepted document, evidence source, and standing instruction. It never infers success from form state.
- Imported — the validated manifest was atomically persisted and read back.
- Unchanged — the retained manifest is structurally identical; no write occurred.
- Conflict — the retained manifest differs and remains untouched. Review its readback, then explicitly select replace if appropriate.
- Rejected — no project was accepted; the path and reason explain the refusal.
The full adoption behavior and exact selection refusals are the kronika init contract. GUI request and session refusals are listed in the runbook.
Accepted imports also record first success for an existing onboarding attempt. The separate Onboarding row reports completion, no completion recorded, or Not recorded with the original bookkeeping cause. The API retains that outcome in result.onboarding.completed and result.onboarding.error. A damaged onboarding file does not undo an imported project or change its success badge. Correct the named state problem and repeat the import; an unchanged manifest can still record first success. Conflicting and rejected imports do not record it.
Readback distinguishes an absent retained manifest from an unreadable one. A failed manifest read or JSON parse refuses the request with the manifest path and underlying cause, including on a conflicting or rejected import; it is not returned as project: null. The graphical result shows Request refused and the same cause. Repair the named file and repeat the import; do not delete a retained manifest to hide a read failure.
The repository journey node tests/gui/retained-manifest.mjs starts the actual CLI server and imports an isolated project through HTTP. Supply KRONIKA_TEST_CLI_BIN, KRONIKA_TEST_SOURCE_REVISION and KRONIKA_TEST_SUCCESS_EXIT. It checks persisted readback, malformed JSON, real symlink-loop and directory-read refusals, unchanged input bytes and repeat-import recovery, retaining requests, statuses, process output and cleanup errors under .build/retained-manifest. This API journey does not substitute for a Weles-driven graphical review on the dedicated host.
Local session security
The GUI is a local administrative surface, not a network service. Every API request must carry a 256-bit per-process token. Mutation additionally requires the exact printed origin; every request requires the exact 127.0.0.1:<port> host, preventing alternate-host and DNS-rebinding use. JSON bodies are capped at 65536 bytes before parsing. The frontend uses DOM text nodes for repository paths, reasons, and manifest values, and the server applies a self-only content security policy, frame denial, no-referrer policy, and no-store responses.
Persistence boundary
Import writes the selected manifest atomically after the core importer validates the entire repository-confined selection, then separately records onboarding first success. It does not copy or change documents, write sync state, call Brama, infer or generate prose, execute Git or package scripts, deploy anything, or invoke tests and validation. Later kronika sync consumes the same manifest.