product
Product Direction
Goal
Choral Forma should make complex project knowledge easier to maintain, read, and reuse by both humans and AI Agents.
The product should help people maintain a structured, normalized, versioned knowledge base that is friendly for human reading and reliable as Agent context. Many human and Agent mistakes begin with insufficient context or low-quality context; Choral Forma should reduce that failure mode.
Users
Choral Forma should serve teams and individuals doing complex, process-heavy work. This includes software, internet products, scientific research, sales, manufacturing, operations, and one-person company workflows.
The product should not assume one team type, one industry, or one canonical information architecture. It should be simple at the core and flexible enough for users to create their own structures, schemas, modes, and templates.
Product Principles
Choral Forma should not be treated as only a Markdown editor. It should become a repository-backed knowledge compiler that continuously turns raw sources, human decisions, Agent analysis, and project artifacts into auditable, linked, maintainable canonical knowledge.
- Keep the core simple, like a general note or knowledge app, while allowing many usage patterns to emerge.
- Treat repository files as durable state, but do not assume users understand Git concepts.
- Support human-readable knowledge and Agent-friendly context as equally important outputs.
- Make structured knowledge approachable for non-software professional users.
- Prefer user-configurable structures over hard-coded product assumptions.
- Make hidden context, stale context, and poor context quality visible.
- Treat validation as diagnostic-first rather than enforcement-first because repository files remain directly editable throughout the product lifecycle.
- Model repeatable note types as spaces: a named set of related entries with a source location, schema, templates, references, and views.
- Keep spaces thin. They should explain files, not become a heavyweight database, permission, or workflow engine.
- Support user-defined semantic types instead of hard-coding product concepts such as people, projects, statuses, priorities, customers, or machines.
- Treat GUI and CLI as first-class product interfaces. Agent and Skill flows should assist and orchestrate product capabilities, not replace them.
Relationship To Repository Forma Practice
The current knowledge/ directory is not a direct product specification for a future Choral Forma user workspace. It is the development knowledge base for this repository and has its own workflow rules, schemas, member conventions, planning model, and Agent skills.
At the same time, this repository's Forma-managed knowledge practice is an early practice ground for Choral Forma's product thesis. It should be treated as dogfooding, prototype practice, and an evidence source for product design.
Practices that prove useful in this repository should become candidates for Choral Forma capabilities. Practices that are shaped by this repository's toolchain, historical choices, or development-team context should be abstracted before being promoted into product requirements.
Working rule:
repository Forma practice = early practice and evidence
future Choral Forma = productized capabilities abstracted from practice
The repository practice can therefore inform product design, but it should not automatically constrain product workspaces. When a repository convention conflicts with a cleaner product model, the product design should identify the underlying user value, compatibility need, and migration cost before adopting or rejecting that convention.
Relationship To Choral Flows
Choral Forma and Choral Flows share the same underlying knowledge runtime thesis, but productize it for different users and interaction surfaces.
Choral Forma is the professional productization path. It keeps repository-backed Markdown, spaces, schemas, semantic types, structured views, reviewable diffs, health checks, and Agent-readable context close to the surface so knowledge maintainers and Agent workflow builders can control the structure directly.
Choral Flows is the business-user productization path. It hides repository and schema mechanics behind business objects such as Matter, Message, Handoff, Proposal, Work Record, Agent, Skill, and Knowledge Promotion so ordinary users can operate through work context rather than knowledge-engineering mechanics.
Working distinction:
Choral Forma = professional knowledge engineering workspace.
Choral Flows = business collaboration runtime.
Choral Forma should not be treated only as a companion tool for Choral Flows. It can serve software teams, research teams, consulting teams, operations teams, one-person companies, and Agent workflow maintainers that need durable, reviewable, repository-backed knowledge. Choral Flows may later use Choral Forma-style capabilities to maintain Starter Kits, Agent Definitions, Skills, Workflow Definitions, and Knowledge Promotion materials, but the two products should keep separate user models and product surfaces.
A Choral Forma repository may also be consumed by Choral Flows as a Git-backed knowledge source. In that model, Forma remains the professional authoring and governance source, while Flows installs the repository as a Workspace Data Source and governs operational use through Workspace, Project, Matter, Agent, Skill, and permission policies. This should be treated as integration, not full migration from Forma into Flows.
Choral Flows does not face the same direct-file inconsistency problem because users operate through product surfaces and knowledge documents are handled by the server. Choral Forma has a larger inconsistency surface because repository files remain directly editable. It should still borrow Choral Flows' broader workflow idea: maintenance problems should become observable, attributable, diagnosable, and repairable through structured findings, reviewable changes, tasks, or Agent workflows instead of only being printed as errors.
Behavior
Flexible Knowledge Spaces
Choral Forma should let users define structures that fit their own work. A future workspace may use notes, tasks, processes, decisions, research, meeting records, designs, operating procedures, sales workflows, manufacturing checklists, or other domain-specific documents.
Default templates and schemas can help users get started, but the product should allow custom structures, schemas, modes, and templates instead of forcing the current repository's knowledge/ layout onto every user.
Astro Content Spaces are a useful reference for this model. In Choral Forma, a space should mean a group of related knowledge entries with a defined source, schema, template, references, and view behavior. A space could represent decisions, experiments, customer notes, manufacturing issues, sales opportunities, operating procedures, or any domain-specific note type.
The important product idea is not Astro compatibility. The useful idea is that "a pile of Markdown files" can become a typed, validated, queryable set without turning Markdown into a database export format.
Spaces And Schemas
Spaces should provide the bridge between a simple note app and structured knowledge work.
Current product direction favors a thin space model. A space definition should initially focus on:
- A name and human-readable purpose.
- A file source expressed as workspace-relative include and exclude globs.
- A schema for frontmatter or structured metadata.
- A default template for new entries.
- Simple membership invariants such as a frontmatter discriminator.
- Field semantic mapping and create-time defaults.
- Managed views such as list, table, kanban, and later calendar.
Schemas should make structure visible and checkable, but should not force every workspace into one information architecture. Users should be able to start with plain notes, then promote repeated patterns into spaces when the structure becomes valuable.
More advanced concepts such as lifecycle rules, permissions, strict process automation, complex loaders, and deep validation should remain outside the thin space core until the product has stronger evidence.
Recommended MVP space responsibilities:
- Discover files.
- Validate metadata shape.
- Create new entries.
- Explain field semantics.
The space model should not become the first place for lifecycle policy, permissions, workflow automation, executable hooks, or external data loading.
include should be the primary source field name rather than path. It should be a required workspace-relative glob. The MVP can start with one include glob string per space. exclude should be an optional list of workspace-relative globs.
A file should match at most one space after excludes are applied. Multiple space matches should be reported as health issues. Candidate files that match include and are not removed by exclude should then be checked against the space's schema. P0 space schemas should use a kind const field as the frontmatter discriminator.
The Markdown body should remain free-form. Body structure constraints should be expressed through templates and guidance rather than hard validation in the space MVP. Health checks may warn about empty or obviously incomplete bodies, but a file should not fail space membership only because its headings differ from a template.
P0 should use a Forma-native YAML Schema DSL as the canonical object constraint language. JSON Schema should not be the P0 authoring format. Runtime tools may derive internal validation plans or exported JSON Schema from the Forma Schema DSL when useful.
The Schema DSL should be used wherever Choral Forma needs object structure or field constraints, not only for space entries. Future create inputs, update inputs, view params, workflow inputs, starter manifests, and diagnostics can use the same schema primitives instead of inventing separate constraint syntaxes.
Example P0 starter space configuration node at .forma/spaces/tasks.md:
---
schemaVersion: 1
kind: term
taxonomy: spaces
title: Tasks
description: Delivery tasks tracked as ordinary Markdown pages.
include:
- "tasks/**/*.md"
create:
directory: "tasks"
filename: "{{ input.slug }}.md"
template: ".forma/spaces/templates/task.md"
inputs:
title:
required: true
summary:
default: ""
slug:
type: string
default: "{{ input.title }}"
transform: slugify
status:
type: select
default: todo
readiness:
type: select
default: needs-refinement
schema:
type: object
fields:
kind:
type: string
title:
type: string
summary:
type: string
status:
type: taskStatus
readiness:
type: taskReadiness
assignees:
type: list
items:
type: member
conventions:
titleField: fields.title
summaryField: fields.summary
createdAtField: fields.createdAt
---
Space paths such as template, create.directory, and create.filename should be workspace-relative paths, not knowledge wikilinks. The default starter layout above means a task entry for a member registration task is tasks/user-registration.md: tasks is the space id, and tasks/ is the space's default entry directory.
Space schema should describe entry metadata structure, user-facing labels, and semantic field constraints. Useful P0 field properties include:
status:
type: taskStatus
label: Status
description: Current delivery state.
required: true
readonly: false
hidden: false
Use label for fields, enum values, buttons, and parameters. Use title for content objects, spaces, views, and pages.
P0 Schema DSL primitives can include:
object
string
number
integer
boolean
date
datetime
const
enum
entryRef
list
required should be field-local in the Forma Schema DSL, such as schema.fields.title.required: true, rather than a JSON Schema-style required: [title] array. Field-local required constraints are easier to merge, patch, review, and edit with Agents.
default does not belong in space schema fields in P0. Defaults are operation-level behavior and should live in create or update input configuration, templates, runtime values, or later migration rules. readonly and hidden should be treated as product and tool behavior hints, not security permissions.
Space conventions can name common semantic fields such as titleField, summaryField, and createdAtField. These conventions should help creation, display, and Agent explanation, but they should not define view layouts. Health checks should validate referenced schema fields. Fallbacks are allowed when no convention exists, but they should be explainable; for example, title can fall back from title to name, displayName, and finally the file basename.
Views should reference spaces by id. They should not redefine space schema fields. Spaces should not define view layouts. Query operators should be validated from space schema field types and cardinality. Display fields, sort fields, kanban fields, and parameter references should be checked against the target space and view parameter definitions.
Semantic Types
Choral Forma should keep built-in data types small and allow users to define domain semantics through configuration.
Base types can include strings, numbers, integers, booleans, dates, datetimes, objects, lists, maps, and paths. Product concepts such as user, group, project, customer, machine, priority, or taskStatus should be user-defined semantic types rather than hard-coded system primitives.
Semantic types can be backed by:
- Static enums declared in configuration, such as status, priority, risk level, or review state.
- Entries from a space, such as members, customers, accounts, machines, or projects.
Space-backed types make a space's entries available as a type. For example, a members space can define the allowed values for a member semantic type. Other schemas can then use that type as a single value, a list value, or a map key or value.
The MVP type model should support:
types:
taskStatus:
kind: enum
values: [todo, doing, done]
member:
kind: entryRef
source: .forma/spaces/members
input:
transform: slugify
Enum values can start as simple scalar values. Later versions can allow richer value objects with label, icon, color, description, or ordering metadata.
Space-backed types imply knowledge reference behavior. Union types are a useful future capability for closely related reference classes, such as members and groups in an assignee field, but they should not be part of P0. When union types are introduced, they should be constrained enough to remain explainable and should not become a general-purpose way to combine unrelated data shapes.
Space-backed types may define input normalization for bare user-entered values:
types:
note:
kind: entryRef
source: .forma/spaces/notes
input:
transform: slugify
This applies only while parsing bare GUI, CLI, or Agent input. It does not change stored ids, stored references, path matching, Markdown-body wikilink matching, schema validation, template rendering, or exact reference comparison.
Example behavior:
Galen -> slugify -> galen -> members/galen.md
members/Galen -> exact path-like input
This is not title search. It only helps map human-entered labels to path ids when the workspace follows slug conventions. P0 should support slugify as the only type input transform.
Cardinality belongs on fields rather than type definitions. The same semantic type can be used as a single value in one field and a space of values in another field.
This lets Choral Forma support many domains without embedding industry-specific objects in the product. The system provides composition mechanisms; users define their own vocabulary.
References In Metadata
Choral Forma should distinguish knowledge references from file, resource, and configuration path references.
Knowledge references point to knowledge entries, such as members, groups, projects, tasks, decisions, customers, machines, topics, or other user-defined spaces. Fields with space-backed semantic types are knowledge reference fields.
Knowledge reference fields should store workspace-relative path-qualified refs in Markdown metadata because the user intent is to refer to a typed knowledge object, not to encode an editor-specific link syntax:
assignees:
- members/alex-chen
project: projects/choral-forma
The product should use read-wide, write-strict behavior. GUI, CLI, Agent, and editor-extension writes should always write canonical path refs. If the product chooses to accept manually authored wikilinks in metadata, that should be a reader convenience and health-check surface, not the canonical storage format or a commitment to Obsidian/Foam compatibility.
The resolver scope should come from the field's semantic type. For example, assignees can resolve only against allowed member spaces in P0, rather than searching the whole workspace. Ambiguous bare or non-canonical references should produce a health check finding instead of being guessed.
File, resource, and configuration references should also use workspace-relative path strings. Their field schema, not the string syntax, should distinguish them from knowledge entry references:
template: .forma/spaces/templates/task.md
sourceFile: attachments/acme-contract.pdf
The WebApp should treat WorkspaceFile as the first-class navigation object. Knowledge documents, views, templates, config files, generated indexes, and resources share the same file inventory shape, while server-assigned features drive render and preview affordances.
Heading or block references should not be valid for space entry reference fields in the MVP. They can remain body-link features, but metadata references should resolve to entry identities.
Internally, Choral Forma should normalize path refs into typed resolved references. The initial resolved identity can be the target file path. Queries, views, health checks, and Agent tools should compare resolved references rather than raw string syntax.
Body Link And Reference Forms
Forma should support multiple body-level link and reference forms without making Obsidian, Foam, or another editor the compatibility target. The product-owned model is a resolved reference with source, intent, target kind, path, optional fragment, optional display text, and optional relationship metadata.
The first supported set should include:
| Form | Example syntax | Required support |
|---|---|---|
| Path-qualified page wikilink | \[\[notes/project-brief\]\] |
Resolve to a page target and record intent: link. |
| Wikilink alias | \[\[notes/project-brief|Project Brief\]\] |
Resolve by path and use the alias as display text. |
| Heading fragment | \[\[notes/project-brief#Goals\]\] |
Resolve the page separately from the heading fragment. Heading validation and scroll targeting can be phased in after page resolution exists. |
| Same-page heading fragment | \[\[#Goals\]\] |
Treat the current page as the target path and resolve the heading fragment. |
| Block fragment | \[\[notes/project-brief#^risk-block\]\] |
Resolve the page separately from the block fragment. Block identity validation can wait until Forma has a stable block anchor model. |
| Same-page block fragment | \[\[#^risk-block\]\] |
Treat the current page as the target path and resolve the block fragment. |
| Wikilink embed | !\[\[notes/project-brief\]\] |
Record intent: embed without expanding embedded content in P0. |
| Heading or block embed | !\[\[notes/project-brief#Goals\]\] |
Record intent: embed with the resolved page and fragment; actual transclusion can wait. |
| Markdown link to workspace page | [Project Brief](notes/project-brief.md) |
Resolve workspace-relative Markdown links into the same reference model as wikilinks. |
| Markdown link with fragment | [Goals](notes/project-brief.md#goals) |
Resolve the page and fragment separately. |
| Resource or attachment link | [Spec](assets/spec.pdf) or !\[\[assets/diagram.png\]\] |
Resolve as a resource target rather than a page target when the path is not an indexed knowledge entry. |
| Field reference relation | assignees: [members/alex-chen] |
Resolve through schema-declared field semantics and record intent: reference. |
The following forms remain tentative until product evidence or implementation constraints justify them:
| Form | Example syntax | Tentative status |
|---|---|---|
| Unqualified title or basename wikilink | \[\[Project Brief\]\] |
Useful for hand-authored notes, but should only resolve when unique and should not be emitted by Forma writes. |
| Case-insensitive or slug-normalized matching | \[\[Members/alex-chen\]\] |
Can produce diagnostics and suggestions, but should not silently resolve because filesystem behavior differs by platform. |
| Heading subtree transclusion | !\[\[notes/project-brief#Goals\]\] |
Rendering the whole section under a heading is a reader/transclusion feature, not just reference resolution. |
| Full Obsidian block-id compatibility | \[\[notes/project-brief#^risk-block\]\] |
Forma may read common ^id anchors, but should define its own block identity rules before promising compatibility. |
| Query or Dataview-style embeds | query blocks or plugin-specific syntax | Forma should use its own view/query model instead of adopting plugin-specific query languages. |
| Tag links as graph edges | #priority |
Tags can support filtering and search, but should become graph relations only through explicit graph edge configuration. |
| Bare URL graph relations | https://example.com |
External URLs should be recognized as external links but not rendered as internal graph edges by default. |
| Proprietary editor graph formats | Canvas or block-graph files | Out of scope unless they can be represented as normal repository files and explicit Forma view/config data. |
Fragment support should split target resolution into a page/resource path and a fragment component. A fragment link should not be resolved as a literal filename containing #. Health checks should distinguish a missing page, an unsupported fragment kind, and an unresolved fragment within an existing page.
Body relationship scanning should ignore Markdown links, wikilinks, and embed examples inside fenced code blocks and inline code spans. Code examples are documentation content, not knowledge relationships, so they must not enter indexing, diagnostics, Definition results, or the reference graph. An editor adapter may expose a separate lexical navigation projection for explicit links inside inline code or blocks labelled md or markdown. This projection may provide native DocumentLink navigation, but it must not style source syntax, apply to other fence languages, replace the Markdown grammar, or intercept native commands.
Forma should later consider an explicit diagnostic suppression syntax for intentional health exceptions. The first design should be narrow and reviewable, for example forma-ignore-next-line, forma-ignore-start, and forma-ignore-end HTML comments that require a diagnostic code and a short reason. Suppression should normally affect diagnostics rather than raw reference extraction, and health output should be able to report suppressed diagnostics instead of silently hiding them. File-level suppression should wait until there is evidence that line-level and region-level suppression are insufficient.
Schema Format
Choral Forma should not use code-based schema frameworks as the user-facing schema configuration format in the product direction for the visible future.
Forma Schema DSL should be the user-visible schema layer. It avoids making Node.js or a JavaScript runtime a hard dependency, keeps object constraints in YAML alongside space configuration, and lets Choral Forma express product semantics such as references, labels, readonly fields, and hidden fields without custom JSON Schema extension keys.
JSON Schema can remain an export, compatibility, or advanced integration format later, but it should not be required in the P0 minimal starter. Forma can derive internal validation plans or exported JSON Schema from the Forma Schema DSL when useful.
Git-Backed Starter Kit Registry
Choral Forma should consider a Git-backed Starter Kit Registry so official teams, community contributors, and private teams can publish reusable knowledge workspace starter kits through ordinary repositories.
At a high level, a registry should let a repository declare one or more installable Starter Kits in a conventional, inspectable way. A Starter Kit should be able to initialize or extend a Choral Forma workspace with knowledge structures such as spaces, schemas, semantic types, templates, views, health checks, workflow rules, examples, and optional Agent or Skill guidance.
The registration mechanism should stay lightweight and repository-native. Choral Forma should be able to discover, inspect, and install a kit from an approved source without requiring a centralized marketplace in the initial product. Users should be able to preview planned file changes, review diffs, and run health checks before accepting the result.
Early design should treat Starter Kits as knowledge workspace structure, not as executable plugins. Arbitrary install hooks, shell scripts, network access, or post-install code execution should remain out of scope unless a later capability model explicitly governs them.
The exact declaration format, registry layout, kit reference syntax, trust model, and update workflow should be designed later.
Starter Kit Initialization Principles
Starter Kit installation should initialize both knowledge content and workspace configuration. The generated workspace should include a .forma/ configuration directory alongside repository-backed knowledge content.
Recommended responsibility split:
.forma/ = workspace configuration.
knowledge/ = repository-backed knowledge content.
skills/ = canonical Agent skill sources.
.agents/ = optional installed Agent runtime entrypoints.
.forma/ must not become a hidden knowledge store. It should explain and configure repository files, not replace them as the source of truth.
Working rule:
If users need to read, cite, review, or discuss it, it belongs in knowledge/.
If tools need to validate, render, create, or inspect it, it belongs in .forma/.
If Agents need to follow it as reusable skill behavior, it belongs in skills/.
If an Agent runtime needs a discoverable entrypoint, it belongs in .agents/ or AGENTS.md.
Starter Kit setup should ask for the canonical language and the supported languages. The canonical language remains the source-of-truth language for durable knowledge. Supported languages describe the languages the workspace intends to support for localized knowledge, labels, templates, Starter Kit copy, and future translation freshness workflows.
Starter Kits may initialize Agent compatibility content. Choral Forma should treat skills/ as the canonical source layout for reusable Agent skills, while .agents/ and AGENTS.md are installed runtime entrypoints that make those skills discoverable to Agent applications. Platform-specific entrypoints such as CLAUDE.md, .claude/skills, GEMINI.md, or similar files should normally be symlinks to installed Agent entrypoints or generated from canonical skill sources.
Choral Forma targets professional users and may assume a development-like environment where repository-local symlinks are supported. Import wrappers or generated copies are exceptional compatibility fallbacks, not baseline product behavior. Compatibility entrypoints should derive from canonical skill sources rather than becoming independent sources of truth.
When the Forma workspace initialization flow is reintroduced, it should create the Forma CLI Agent bootstrap skill as part of the starter workspace rather than requiring a separate forma skills init or forma skills install command. The initialization output should include skills/forma-cli/SKILL.md as the reviewable source file and .agents/skills/forma-cli/SKILL.md as the installed Agent runtime entrypoint. Existing files should not be overwritten without an explicit force or review flow.
The P0 minimal starter should include enough structure to demonstrate Choral Forma's knowledge, action, and lightweight collaboration model without becoming an opinionated project-management workflow.
Recommended P0 minimal starter spaces:
notes
tasks
members
decisions
proposals
guidelines
notes represents general knowledge notes. tasks represents lightweight action items. members represents people who can be referenced in the workspace. decisions records accepted direction, proposals captures reviewable changes, and guidelines keeps human- and Agent-readable operating guidance.
The P0 starter should not include groups or union semantic types. Groups introduce membership, responsibility, and organizational modeling that should wait until P1. Task assignment should still be modeled in a future-compatible way:
assignees:
type: list
label: Assignees
items:
type: member
When groups are added later, the assignees field can keep its name and list shape while its item target evolves to an assignee union over member and group.
The P0 members space should keep identity lightweight. A member entry's stable id comes from its path-qualified entry reference, such as members/alex-chen. P0 should not include a separate username field because it would act like a field-level override for path identity. Runtime current-member matching should use the member id directly.
Workspace initialization is currently disabled pending redesign. When initialization returns, it should not treat the current member as a special system value. If an initial member entry is created during initialization, it should be handled as ordinary starter input and created through the same space create pipeline as any other member entry.
Product Naming In Workspace Surfaces
Choral is the brand name; Forma is the product name. Product-specific workspace surfaces should use Forma naming:
CLI command: forma
configuration directory: .forma/
product docs: Choral Forma
brand and ecosystem references: Choral
The choral name should remain available for brand-level or future cross-product capabilities instead of being consumed by the Forma MVP.
Human And Agent Collaboration
The product should help humans and AI Agents maintain a shared context base. Agents should be able to search, inspect, validate, summarize, and update knowledge through explicit files, schemas, CLI commands, and skills.
When Agents assist with workflows such as conflict resolution, pull requests, schema checks, or workspace health checks, the product should guide the human without requiring them to understand the underlying Git mechanics.
Agent and Skill flows should be an assistance layer over stable product capabilities. Core actions such as creating spaces, editing semantic types, building views, inspecting effective config, and running health checks should be available through GUI and CLI. Agents can suggest, explain, draft, orchestrate, and repair, but the product should not depend on Agents as the only way to use these capabilities.
Forma operations are the durable product surface for knowledge management. Agent skills should call those operations and keep only orchestration policy, review discipline, and user-specific workflow behavior. MCP should be treated as a transport adapter over stable operations, not the first implementation target for replacing local skill mechanics.
Manual edits, Git merges, incomplete drafts, stale derived artifacts, and Agent work-in-progress may create temporary inconsistencies. Choral Forma should read and inspect imperfect files with diagnostics where possible. Product commands should avoid knowingly writing invalid content, while forma check should make workspace inconsistencies explicit enough for humans or Agents to repair manually or through future reviewable repair workflows.
Executable Knowledge
Some process definitions should be stored as structured knowledge. Humans and Agents should be able to follow those definitions to move work forward.
This should be treated as a product concept: process knowledge can define expected inputs, states, checks, transitions, review points, and outputs. It is not application code, but it should be executable enough for people and Agents to coordinate consistent work.
Collaboration And Personal Workflow Boundaries
Human and Agent workflows need to distinguish durable team facts from personal drafts, scratchpads, execution plans, preferences, and runtime state. This is a collaboration and promotion concern in P0, not a built-in content visibility scope.
Repositories may use Git tracking, review guidance, ownership metadata, and explicit user context to decide what becomes durable team knowledge. Forma still treats every configured input as part of one effective workspace; it does not infer privacy or visibility from those workflow conventions.
Promotion of personal working material into durable repository content should remain explicit and reviewable. A future product-level visibility model requires its own configuration, authorization, publication, and migration contract.
Effective Configuration And Personal Workflow State
P0 has one effective workspace configuration. .forma.md is the entry point, and every valid explicitly configured import participates in the same merge regardless of its directory name or Git tracking state. Forma does not assign shared, personal, private, or publication scope from .gitignore or a path such as .forma/local/.
The P0 resolution order is:
.forma.md + validated configured imports -> effective configuration -> runtime values
Runtime values are not written back into configuration files. They are available for interpolation, effective configuration inspection, health checks, and view or template rendering.
Recommended target layout:
.forma.md
.forma/
pages/
*.md
spaces/
*.md
views/
*.md
templates/
assets/
Repository workflows may keep personal drafts or machine-specific files uncommitted, and a workspace or host application may use ignored paths for caches, locks, local indexes, or GUI state. That workflow boundary is not a Forma runtime privacy boundary. Secrets, credentials, and material that must remain private should stay outside configured workspace inputs.
P0 does not define a separate local-override scope. Future profile or configuration-layer support requires an explicit product contract for selection, precedence, visibility, publication, and migration rather than a special directory convention.
Future profile configuration can use explicitly imported configuration fragments when the product has enough durable profile preferences to justify it. Profiles should not be selected automatically by a built-in user or member identity mechanism.
A workspace may place shared profile fragments at any explicitly referenced workspace-relative path, for example:
config/profiles/<profile-name>.md
This example is not a built-in Forma path. If profiles are introduced, their selection and merge order must stay explicit:
base configuration -> explicitly selected profiles -> runtime values
The profile path is the selection dimension. A workspace may choose to relate profiles to entries in a members, people, agents, or other user-defined space, but Forma should not require or infer that relation from the path.
Strict team enforcement is not an initial requirement. The more important need is a clear merge model and Agent-friendly CLI or skills that can explain the effective configuration, show where each value came from, and check workspace health, configuration consistency, and schema validity.
MVP import-merge semantics should remain simple and explainable:
object: deep merge
array: replace
scalar: replace
null: explicit empty value
missing: inherit
delete/unset: not supported
array append/remove: not supported
same-layer conflict: invalid unless a file boundary explicitly owns it
Configuration sections and imported files should have clear responsibility boundaries:
.forma.md owns the main configuration entry and imports.
workspace owns identity, language, timezone, and presentation metadata such as logo.
runtime owns runtime values.
Markdown config nodes under .forma/spaces/ own space schemas and starter space taxonomy terms.
Markdown config nodes under .forma/spaces/templates/ own create-time content templates.
Markdown config nodes under .forma/views/ own saved projection definitions.
Navigation configuration owns sidebar and prominent route/page/view groups.
The effective configuration should be inspectable instead of hidden. CLI and Agent-facing interfaces should be able to show the merged configuration, explain which source produced a specific value, and check for merge conflicts, invalid types, circular references, unsafe paths, and values that depend on the current machine.
The product should avoid writing an effective configuration file as a durable source of truth. If caching becomes necessary, caches should live under project-ignored paths and remain uncommitted.
Schema, Guidelines, Policies, Invariants, And Operations
Forma should separate knowledge constraints into distinct layers:
schemadescribes document structure, field types, required fields, enum values, semantic references, and create defaults.guidelinesare ordinary Markdown knowledge documents referenced by workspace configuration, taxonomy terms, views, or future operation profiles. They explain collaboration conventions, write boundaries, review expectations, project-specific operating rules, and lightweight Human/Agent procedure checklists.policiesare future machine-readable constraints for write operations and workflow transitions, such as task status transitions or review gates.invariantsare workspace-wide consistency checks, such as resolved references, unique space membership, canonical/localized variant consistency, and safe config paths. Any future visibility or publication exclusion must be explicitly configured rather than inferred from path names.operationsare the CLI/RPC/WebApp actions that read, propose, validate, apply, and audit changes using schema, policies, invariants, and guidelines.
Guidelines should be introduced before a full policy engine because they replace the soft procedural constraints that were previously carried by Agent skills. Policies should be added only when a writable operation needs machine-enforced preconditions.
The deferred Actions and Triggers model is captured separately in product/forma-actions-triggers-concept. It should stay P1+ until single-entry write operations and reviewable change proposals are concrete enough to consume it.
Managed Views
Views should be managed Markdown definitions under .forma/views/**/*.md. They are file-based facts, but not ordinary knowledge notes. Their frontmatter defines rendering behavior; their Markdown body explains purpose, usage, and maintenance context.
The durable architecture for view sources and queries is captured in architecture/forma-view-query-model. This section keeps the product-facing behavior and examples aligned with that model.
Shared view definitions should live as Markdown configuration nodes under .forma/views/, not in the ordinary knowledge content tree. A view is configuration for rendering, filtering, and organizing knowledge; it is not itself a domain knowledge entry. Keeping view definitions under .forma/ preserves the file-as-fact principle while making the boundary clear.
The view file should be recognizable through explicit frontmatter:
---
kind: view
surface: page
mode: table
title: My Tasks
description: Active tasks assigned to the current member.
source:
type: pages
taxonomy:
spaces:
- tasks
---
The view data source should be recognized pages. source selects the candidate page set; query filters normalized entries derived from those pages. Taxonomy-oriented views should use list-valued taxonomy filters. This:
source:
type: pages
taxonomy:
spaces:
- tasks
filters recognized pages before query predicates run. This keeps taxonomy filters explicit while avoiding a separate hardcoded entry.space field.
The Markdown body should not contain query logic. It can include a render mount point:
<!-- forma-view -->
Exactly one mount point is required for a source-backed View preview. If no mount point or multiple mount points exist, render operations and health checks should report the problem with an actionable source location instead of guessing where generated content belongs.
Views should have a surface:
page
embed
P0 managed views should only require directly accessible page views. embed views and view embedding syntax are important P1 design targets, captured here to protect the model, but they should not be treated as required for the P0 starter or first implementation.
page views are directly accessible full views. They can appear in view navigation, have complete page layout, and expose filtering or sorting controls where the mode supports them.
embed views are reusable view fragments intended for inclusion inside other Markdown documents. They should not appear in ordinary view navigation by default. They can still be inspected or previewed for maintenance.
The MVP should keep one primary surface per view file. If a team needs both a page view and an embedded fragment, it can define two view files with related queries. Shared query abstraction can wait until there is stronger evidence.
View definitions may support declared parameters. P0 page views may omit parameters entirely. View parameters are optional for P0 page views and should be required when P1 embedded views ship. Parameters can have base types or user-defined semantic types, can have defaults, and can be referenced from view metadata, query values, mode-specific configuration, and body text:
params:
member:
label: Member
type: member
required: true
default: "{{ runtime.values.currentUserId }}"
date:
label: Date
type: date
default: "{{ runtime.values.currentDate }}"
Page view parameter values can come from defaults, URL or GUI state, or CLI parameters. Embedded view parameter values should come from the embedding comment, falling back to defaults where available. Unknown parameters, missing required parameters, and invalid parameter values should be diagnostics.
Embedded view parameters are required for a useful embed model. Without them, teams would need one view definition for every member, project, or reporting period. P1 embedded views should therefore include parameter support rather than shipping fixed-only embeddings.
Knowledge documents should be able to embed existing views with Markdown HTML comments:
<!-- forma-view: member-active-tasks member="members/alex-chen" -->
<!-- forma-view: project-open-tasks project="{{ params.project }}" -->
The identifier should resolve to a view file, such as .forma/views/member-active-tasks.md. Embed arguments should be type-checked against the target view's view.params. The initial argument model should stay small: string, number, boolean, date, semantic reference literals, and {{ ... }} path placeholders. It should not support expressions, loops, conditions, or complex object literals.
Definitions and embeddings are separate concepts:
.forma/views/*.md = view definition
knowledge Markdown comments = view embedding sites
View queries should operate on normalized entry records, not directly on raw Markdown files. The runtime should first parse each candidate Markdown file into an entry record with stable namespaces such as:
entry = {
path: "tasks/review-webapp.md",
taxonomies: {
spaces: ["tasks"],
},
kind: "task" | null,
fields: {},
refs: {},
text: {},
};
The query model should use structured all / any / not nodes rather than a text query DSL in the MVP. Query predicates should use explicit field paths into the normalized entry record:
source:
type: pages
taxonomy:
spaces:
- tasks
query:
all:
- field: fields.status
op: in
value: [todo, doing]
- any:
- field: fields.priority
op: equals
value: high
- field: fields.blocked
op: equals
value: true
This query model should be treated as the internal query AST. A future text DSL can compile to the same model if product evidence justifies it, but the MVP should avoid taking on parser, type-checking, error-reporting, and GUI round-tripping complexity too early.
Initial query operations can include:
equals
notEquals
in
notIn
contains
notContains
intersects
exists
before
beforeOrEqual
after
afterOrEqual
exists should use an explicit boolean value. For example, uncatalogued field values can be expressed without a special missing operator:
query:
all:
- field: fields.dueDate
op: exists
value: false
P0 can keep query support intentionally small: source.type: pages, source.taxonomy, all, any, not, field: fields.<name>, and the operations equals, in, contains, and exists. References, full-text predicates, date comparisons, diagnostic filters, and saved runtime query controls can remain P1 unless needed by implementation evidence.
View modes should start with list, table, and kanban. Calendar views are valuable for daily, weekly, monthly, and time-based workflows, but should remain P1 unless implementation capacity proves otherwise.
Graph should also be treated as a view mode, not as a separate global product surface. Users should open graph views through normal view navigation, tabs, or links, the same way they open table or kanban views. A graph view can visualize references, backlinks, relationship fields, or a scoped subset of entries, but it should still be described by a view definition with explicit scope and rendering intent. Bottom relationship panels can show backlinks, outgoing links, and mentions for the current document, but they should not be the primary graph surface.
Graph views can use the same page source without a space filter. For example, an initialized workspace can include a global graph view:
---
kind: view
surface: page
mode: graph
title: Knowledge Graph
source:
type: pages
graph:
edges:
- source: body
intent: link
label: links to
- source: body
intent: embed
label: embeds
---
This is not a cross-space table query. It is a graph rendering over the recognized page set and reference graph, so it can include cross-space links without making every view mode support arbitrary space joins.
Graph edge selection should be view configuration, not a global hard-coded rule. The read model can resolve all body and field references, but each graph view should choose which relation classes become rendered edges. Body wikilinks and embeds are relations too, so they should use the same edge configuration shape as structured field references:
graph:
edges:
- source: body
intent: link
label: links to
- source: body
intent: embed
label: embeds
Structured field references should also be configured as edge rules rather than selected by a plain field-name list. source: fields means the field value is relative to the entry's normalized fields object, so assignees is preferred over fields.assignees. Each configured field edge may name its graph label so the rendered edge has user-facing meaning:
graph:
edges:
- source: fields
field: project
label: belongs to
- source: fields
field: assignees
label: assigned to
- source: fields
field: blockedBy
label: blocked by
label is optional. If it is absent, body edges can fall back from intent, and field edges can fall back from the schema field label before using the raw field name. The configured field must resolve to a schema-declared reference field. Health checks should report graph edge fields that are missing, not reference typed, ambiguous, or outside the view's source/query scope. The graph render result should carry the resolved edge label, source kind, reference intent, field when present, and semantic type so the WebApp can style, filter, and explain edges without guessing from raw syntax or field names.
List and table views can use shared query and sort fields, plus mode-specific rendering options such as title fields, subtitle fields, metadata fields, or table columns.
Kanban views should support richer configuration because process-heavy work is central to the product. A kanban view should first select candidate cards with the top-level query, then assign cards to columns with kanban.columns[].query. Columns are evaluated in order and the first matching column wins. Health checks should warn about overlapping columns and unmatched items.
Example kanban configuration:
---
kind: view
surface: page
mode: kanban
title: Tasks
source:
type: pages
taxonomy:
spaces:
- tasks
kanban:
card:
titleField: fields.title
subtitleFields: [fields.project, fields.assignees]
badgeFields: [fields.priority, fields.dueDate]
columns:
- id: todo
label: To Do
icon: circle
query:
all:
- field: fields.status
op: equals
value: todo
onDrop:
set:
status: todo
- id: blocked
label: Blocked
icon: octagon-alert
query:
all:
- field: fields.blocked
op: equals
value: true
onDrop:
set:
blocked: true
---
Drag-and-drop mutation should be explicit. If a column has complex matching logic, the product should not guess how to update a card. onDrop.set should declare the exact field changes that moving a card into the column will make.
View health checks should report missing spaces, missing fields, missing parameters, incompatible operators, invalid default or query values, invalid sort or display fields, invalid kanban onDrop.set fields, overlapping kanban columns, unmatched kanban items, and multiple render mount points.
Cross-space list, table, and kanban views should remain out of the MVP. The initial space view model should make one space understandable and useful before trying to join multiple spaces. This limitation does not prevent graph views from using the workspace source without a space filter.
Runtime temporary query controls, runtime filters, runtime group-by controls, runtime sort overrides, and saved personal view controls are not part of the current direction. Future table views may add advanced table features, but that should be discussed separately from the P0 managed view model.
Agents should read the same view definitions that human-facing UI uses. View definitions should not contain a separate Agent-only context policy. Agents can use view.query, view.params, space schema fields, semantic types, and future view rendering APIs to find candidate entries, then decide which entries to inspect based on the task.
This keeps responsibility clear:
View = selection and display definition.
Agent = task-specific context choice using the same workspace structures.
Agent-friendly output formats such as --json are product interfaces, not a second configuration model. Agent-only workspace configuration should be avoided unless there is a strong safety, permission, or interoperability reason.
Runtime Interpolation
Configuration files and template files should support limited runtime interpolation with {{ ... }} placeholders.
Interpolation should initially be path lookup only. It should not support expression evaluation, function calls, loops, conditionals, shell execution, JavaScript execution, arbitrary environment access, file reads, or network requests.
MVP placeholders can include:
{{ input.<name> }}{{ params.<name> }}{{ runtime.values.currentDate }}{{ runtime.values.currentDateTime }}{{ runtime.values.workspaceRoot }}{{ runtime.values.currentUserId }}{{ config.<dotted.path> }}
Configuration references should resolve against the effective configuration after .forma.md and its validated configured imports are merged. The resolver must detect circular references and report them clearly instead of silently producing partial values.
Runtime values should be explicit definitions under runtime.values.*. In configuration files, runtime.values.<name> defines how to resolve the value. In templates, view params, and resolved contexts, runtime.values.<name> reads the resolved value.
P0 runtime value kinds can include:
const
gitConfig
currentDate
currentDateTime
workspaceRoot
Example:
runtime:
values:
currentDate:
kind: currentDate
currentDateTime:
kind: currentDateTime
workspaceRoot:
kind: workspaceRoot
currentUserId:
kind: gitConfig
key: user.name
transform: slugify
An explicitly imported configuration fragment can replace a runtime value definition with the same shape:
runtime:
values:
currentUserId:
kind: const
value: alex-chen
transform: slugify
P0 should not include a separate memberIdResolver concept. Current-user identity should instead be modeled as runtime.values.currentUserId, a normal runtime value whose provider can normalize environment data into a user id. Member-like or user-like behavior should be derived from spaces, semantic types, and runtime values rather than hard-coded resolver names.
The resolver chain should remain explicit and inspectable. CLI and Agent tools should report which runtime value definition produced a value, which configured source won during the effective-config merge, and why a value is unresolved.
Template files can use runtime placeholders when creating new entries. Committed knowledge entries should generally store resolved concrete values rather than dynamic placeholders as durable facts.
Hugo is a useful reference for mature file-based templates, but Choral Forma P0 should not adopt Hugo's full template expression model. P0 templates should use simple path placeholders only. They should not support default operators, filters, functions, conditionals, loops, includes, partials, expression evaluation, or arbitrary scripting.
Create input defaults can use the same simple placeholder syntax:
create:
inputs:
date:
label: Date
type: date
default: "{{ runtime.values.currentDate }}"
Template placeholders should then stay simple:
date: "{{ input.date }}"
This keeps defaults inspectable in space configuration instead of burying them in template expressions.
Create inputs may also define a small operation-level transform:
create:
inputs:
title:
field: title
required: true
slug:
label: Slug
type: string
default: "{{ input.title }}"
transform: slugify
Transforms are not template functions. They normalize final input values during the create pipeline before filename and template rendering. Runtime value definitions can also use transforms to normalize provider output before the resolved value is exposed to templates or views. P0 should only support a slugify transform. slugify should be deterministic and safe for filenames: trim, lowercase where applicable, normalize whitespace to hyphens, remove path separators and reserved filesystem characters, collapse repeated hyphens, strip leading and trailing hyphens, keep Unicode letters and numbers, and fail if the result is empty.
Future versions may introduce a small declarative DSL for lightweight type conversion, data-structure transformation, filtering, or cleanup. This should remain separate from arbitrary scripting.
Create, Edit, And Inspect Flows
Space-backed create flows should be predictable and reviewable:
choose space
-> collect input
-> generate path
-> render template
-> validate
-> write file
-> show diff/result
Example:
forma create tasks --title "Draft reference model"
Creation should use space.create.directory and space.create.filename. input.* placeholders are create-time values only. Templates can use input, runtime, and configuration placeholders, but committed knowledge entries should store resolved concrete values where possible.
Create inputs are operation parameters, not runtime space schema definitions. Space schema fields and create inputs are separate namespaces. A create input may explicitly bind to a schema field:
create:
inputs:
title:
field: title
required: true
The binding explains that the input corresponds to space.schema.fields.title for type checking, GUI labels, Agent explanation, and diagnostics. Same-name inputs and schema fields do not bind implicitly. If field is absent, the input is a create-only parameter even when it has the same name as a schema field. Templates still decide how inputs are written into generated files.
P0 create input properties can include:
field
label
description
type
required
default
transform
The metadata creation flow should be:
resolve create inputs -> render filename and template -> validate Forma schema
Input resolution should treat inputs as a dependency graph:
- Load declared inputs and explicit user values.
- Build dependencies from
defaultplaceholders that referenceinput.*. - Validate that referenced inputs exist and that there are no cycles.
- Resolve inputs in dependency order.
- For each missing input, render its default after dependencies are resolved.
- Apply the input
transform, if configured, to explicit or defaulted values. - Type-check final values and enforce
input.required.
Dependencies read another input's final value after its transform. Template and filename rendering happens only after all inputs are resolved.
Semantic field context should control serialization. For example, if assignees is a many-valued member reference field, a member id can be serialized as a path-qualified member entry reference. The write should fail before creating an invalid space entry.
The MVP should not require bulk creation, loops, executable hooks, overwrite modes, or multi-file transactions.
Editing should prefer typed patches first and raw edits second. The product should support three levels:
- Structured edit for normal use.
- Raw metadata edit for advanced users and tools.
- Body edit using ordinary Markdown editing.
Examples:
forma set tasks/foo.md status doing
forma add tasks/foo.md assignees members/alex-chen
forma remove tasks/foo.md assignees members/alex-chen
forma unset tasks/foo.md dueDate
set should replace a single-value field or replace the whole value of a many-valued field. add and remove should operate on many-valued fields. unset should remove a field. A later clear command can explicitly set a field to null if that distinction becomes important.
Reference input should be permissive when the field context is known. Users and Agents may provide values such as alex-chen, members/alex-chen, or members/alex-chen.md for an assignees field. Product writes should normalize resolved metadata references to path-qualified entry references such as members/alex-chen. Many-valued reference fields should deduplicate by resolved identity, not by raw string.
Edits should preserve YAML ordering, unknown fields, comments where practical, and the Markdown body. The product should avoid full-document rewrites for small metadata changes. Validation should run before writing, and force writes should remain out of the MVP.
P0 Agent-facing tooling should use stable read, check, and create commands such as:
forma config inspect
forma inspect
forma list
forma create
forma check
P1 structured edit commands can add:
forma set
forma add
forma remove
forma unset
Entry locators should support:
- Workspace-relative Markdown paths.
- Workspace-relative paths with the
.mdextension omitted. - Explicit space-scoped lookup with
--space <space-id> <entry-name>.
Recommended Agent-safe form:
forma inspect --space tasks user-registration --json
For space-scoped lookup, <entry-name> should mean a file basename without .md inside the space's include and exclude result. No-match and multiple-match cases should be errors with suggestions to use a path locator or create a new entry.
Space-scoped bare entry locators may use the corresponding space-backed type input normalization when such a type exists. For example, forma inspect --space notes "Meeting Notes" can normalize the bare entry name to meeting-notes before exact lookup. Path-like locators remain exact and should not be normalized.
With the starter tasks space, forma inspect tasks/user-registration is a path-like locator for tasks/user-registration.md, while forma inspect --space tasks user-registration resolves the same entry through the tasks space.
P0 CLI should prioritize reading, indexing, checking, and inspection before broader write operations. The current write baseline includes bootstrap-only workspace initialization plus minimal create against an existing configured workspace. Starter-kit installation, migration, and broad workspace generation remain future work. Required P0 commands:
- forma config inspect [--json]
- forma config inspect --path <path> [--json]
- forma check [--json]
- forma inspect <path> [--json]
- forma inspect --space <space> <entry> [--json]
- forma list --space <space> [--json]
- forma view render <view-id-or-path> [--json]
- forma workspace health [--json]
- forma skills list [--json]
- forma skills get <id> [--json]
- forma docs list [--json]
- forma docs get <id> [--json]
- forma init [--name <name>] [--language <tag>] [--timezone <tz>] [--json]
- forma create <space> [--input <name=value>]... [--json]
- forma serve
P1:
- forma set <entry> <field> <value>
- forma add <entry> <field> <value>
- forma remove <entry> <field> <value>
- forma unset <entry> <field>
- forma deprecate <entry>
- forma delete <entry>
- forma move <from> <to>
- forma rename --space <space> <old> <new>
- search/query commands
- fix plan/apply commands
- local full index
All read commands should support stable JSON output for GUI and Agent use. Human-oriented output should remain concise and explainable.
forma init should only create the minimal Forma bootstrap in this stage: .forma.md and .agents/skills/forma-cli/SKILL.md. It should not copy starter-kit content, edit AGENTS.md, or generate canonical skills/forma-cli/SKILL.md.
forma create should use configured create inputs, defaults, transforms, and templates, fail on path conflicts, and rely on subsequent read operations to rebuild their in-memory projections from source files. Future starter-kit initialization should be redesigned around the committed starter-kit or an explicit template source rather than a duplicated embedded starter.
CLI confirmation should be based on operation risk. Read-only commands should not ask for confirmation. Single-file, predictable, non-destructive writes can avoid confirmation when they fail on conflicts or invalid inputs. Bootstrap-only forma init can proceed when target paths do not exist and must refuse to overwrite existing bootstrap files. Starter-kit installation, physical deletion, path moves or renames that change references, automatic fixes, batch updates, and multi-file or reference-changing writes should require confirmation.
In current P0, forma create does not require confirmation because it writes one new entry and fails on path conflicts. Future initialization should require confirmation because it would create workspace structure and configuration; interactive shells should show resolved initialization parameters and planned writes before asking for confirmation, while non-interactive shells should fail without writing unless explicitly bypassed.
Lifecycle And Deletion
Entry lifecycle should distinguish knowledge status from file operations.
Task workflow state is part of the P0 starter because the starter uses configured status and readiness fields plus task views to demonstrate lightweight action tracking. Forma should still avoid treating arbitrary fields named status as built-in lifecycle semantics; task workflow meaning comes from the starter's configured space, views, and guidelines.
Entry lifecycle operations such as deprecate, archive, delete, move, rename, and merge should remain outside the P0 minimal starter until their field model, view behavior, check behavior, and Agent context behavior are designed together. If entry lifecycle interpretation is introduced later, it should be configured explicitly rather than inferred only from a field name.
Deprecation remains an important future lifecycle operation. A deprecated file should stay at its original path and remain readable, searchable, and directly openable, while future views or context builders can explicitly decide whether to include it.
The dedicated deprecation command should be P1, earlier than archive or merge:
forma deprecate decisions/old-auth.md --reason "Superseded by the new auth model"
forma deprecate decisions/old-auth.md --replaced-by decisions/new-auth.md
forma deprecate --space decisions old-auth --replaced-by decisions/new-auth
The exact lifecycle schema, replacement relationship, view filtering, and context behavior should be decided with the P1 deprecation design. A separate undeprecate command is not required in the initial deprecation design; restoring active status can remain a deliberate metadata edit until product evidence justifies a first-class command.
Delete should be a dangerous but legitimate future first-class action. Choral Forma is intended for professional, repository-backed workspaces, so the product does not need a heavy application-level recycle bin. Physical deletion should be allowed once the command is designed, and version control can provide history where users adopt it.
Deletion still needs explicit tooling because it affects references:
forma delete decisions/old-note.md
forma delete decisions/old-note.md --replace-with decisions/new-note.md
P1 delete behavior should inspect affected references, show the planned change, physically delete the file when confirmed, and run or recommend a follow-up check. --replace-with should rewrite references that can be safely resolved and report anything ambiguous. More advanced reference cleanup options can wait.
Path should remain the default entry identity in the MVP. Controlled move and rename commands should be the preferred migration path because they can update references and keep space membership valid:
forma move tasks/old-name.md tasks/new-name.md
forma rename --space tasks old-name new-name
Direct filesystem edits should remain allowed. forma check should detect broken references, invalid space membership, ambiguous non-canonical references, stale views, and other consequences before review or commit.
In-Memory Read Model
The first public release should not use a committed summary index. The local server and read operations scan source files and configuration, then keep the read model in memory.
The MVP should not include a committed summary index or a user-visible local full index. A persistent index, SQLite backend, watcher, or vector index can be introduced later only after a fresh design if workspace size, GUI latency, configuration scale, or semantic search make them necessary.
The read model is derived runtime state, not a knowledge store:
source files win
read model supports discovery, graph traversal, and context selection
read model can always be rebuilt in memory
Runtime read-model projections should not contain absolute paths, host cache state, credentials, runtime identity, user behavior traces, full frontmatter, full Markdown bodies, diagnostics, check summaries, health state, effective config, rendered HTML, or rendered view results. Configured workspace entries are not excluded merely because their path is ignored by Git or contains a component named local.
Recommended shape:
{
"schemaVersion": 1,
"workspace": {
"name": "Acme Knowledge",
"canonicalLanguage": "en",
"supportedLanguages": ["en"]
},
"spaces": [
{
"id": "tasks",
"title": "Tasks",
"include": "tasks/**/*.md",
"entryCount": 1
}
],
"views": [
{
"id": ".forma/views/tasks",
"path": ".forma/views/tasks.md",
"surface": "page",
"mode": "kanban",
"space": "tasks",
"title": "Tasks"
}
],
"entries": [
{
"path": "tasks/user-registration.md",
"space": "tasks",
"kind": "task",
"title": "User registration",
"summary": "Implement user registration flow.",
"refs": [
{
"source": "frontmatter",
"field": "assignees",
"targetPath": "members/alex-chen.md",
"semanticType": "member",
"intent": "reference"
},
{
"source": "body",
"targetPath": "notes/account-model.md",
"semanticType": "note",
"intent": "link"
},
{
"source": "body",
"targetPath": "notes/project-brief.md",
"semanticType": "note",
"intent": "embed"
}
]
}
]
}
By default, serve/check operations should scan configured source files and effective configuration into memory. P0 does not need a user-visible persistent index rebuild or index check behavior.
Diagnostics are runtime results that belong to forma check, forma serve, or shared RPC responses; they should not be persisted as a separate diagnostics result file. Effective configuration belongs to forma config inspect; view results belong to view rendering.
Future implementation caches may accelerate checks, parsing, or diagnostics, but they should be local-only, rebuildable, and stored under project-ignored paths. They must not become product facts or public Script/Agent interfaces.
Check Diagnostics
forma check should be read-only and diagnostic-first. It should not repair files in P0. Human output should be concise, while --json should provide stable structure for Agents, scripts, and GUI.
Recommended P0 JSON shape:
{
"status": "failed",
"summary": {
"errors": 1,
"warnings": 2,
"infos": 0
},
"diagnostics": [
{
"severity": "error",
"code": "entryRef.unresolved",
"message": "Reference cannot be resolved.",
"path": "tasks/user-registration.md",
"location": {
"kind": "frontmatter",
"field": "assignees",
"index": 0
},
"actual": "[[members/tics]]",
"expected": {
"type": "entryRef",
"target": "member"
},
"suggestions": [
{
"label": "Use members/alex-chen",
"value": "members/alex-chen"
}
]
}
]
}
P0 diagnostic fields should include severity, code, message, path, location, actual, expected, and suggestions where applicable. Suggestions are advisory only and should not contain patches in P0.
P0 severity values:
error
warning
info
P0 status values:
passed = no errors or warnings
warning = warnings but no errors
failed = at least one error
Warnings should not cause a non-zero exit code in P0. Errors should. A required runtime value that cannot resolve should be a warning unless it blocks a specific operation.
P0 diagnostic code families can include:
config.*
runtime.*
space.*
schema.*
entry.*
entryRef.*
view.*
template.*
create.*
index.*
Editing And Reading Surfaces
The product can support multiple surfaces:
- VS Code or Zed extensions.
- A local service started from the product CLI and accessed through a browser.
- A read-only GUI for browsing, rendering, inspecting, and diagnostics over a local repository workspace.
- CLI commands for inspection, validation, generation, repair assistance, and automation.
- Agent and Skill wrappers over GUI, CLI, and repository operations.
P0 GUI should be a local webapp served by forma serve. It should browse spaces and page views, render table and kanban views, inspect entry metadata and Markdown bodies, show resolved references, and display check status. It should not create, edit, delete, move, rename, deprecate, mutate kanban cards, edit settings or schemas, run Git operations, or perform fixes in P0.
After that read-only baseline, editor extensions become the primary product surface for the next phase. VS Code is the first target, with Zed following after the shared adapter contract is proven. The editor extension should discover .forma.md, surface workspace health, provide Forma-owned reference navigation, and preview Markdown-backed views without replacing their editable source. The WebApp remains a maintained read-only surface rather than the center of new product workflows. The accepted transition is recorded in decisions/editor-extension-primary-product-surface.
Editor adapters must consume shared operations rather than parsing workspace configuration, resolving references, or evaluating views independently. They should enhance the host's native Markdown experience and avoid replacing grammars, navigation providers, preview pipelines, themes, or accessibility behavior when a non-invasive extension point is available. View previews should follow host editor theme and accessibility settings. View source must continue to open as ordinary Markdown, with generated list, table, kanban, or graph content shown as a derived preview at the configured mount.
The user-facing experience should not require users to understand Git branches, merge conflicts, pull requests, or commits. Agents and skills can assist with those operations when they are needed.
In Scope
- Thin configurable spaces, schemas, semantic types, modes, views, and templates.
- Human-readable and Agent-friendly repository knowledge.
- Agent-friendly CLI and skills for health checks, validation, workflow execution, and safe maintenance.
- Editor extensions that reuse shared Forma operations for workspace discovery, navigation, diagnostics, and view preview.
- CLI interfaces for config inspection, check, inspect, list, create, and serving a local read-only webapp.
- Read-only local browser GUI for browsing spaces and views, rendering entries, inspecting metadata, and viewing diagnostics.
- Structured views over files without requiring custom executable scripts.
- Forma-native YAML Schema DSL as the initial user-visible object constraint format.
- Explicit promotion and splitting between personal and shared content.
- Future explicit knowledge visibility scopes, if product evidence justifies them; P0 does not infer them from paths or Git state.
- One P0 effective configuration assembled from
.forma.mdand validated configured imports. - Guidance for non-software users around repository operations that would otherwise require Git knowledge.
- Optional date-based workflows such as daily, weekly, or monthly reports where they fit a user's workspace.
- Limited
{{ ... }}runtime interpolation for configuration and templates. - Create inputs with explicit field binding, operation-level defaults, dependency-graph resolution, and a small
slugifytransform. - Runtime in-memory read model rebuilt from configured source files and effective configuration.
- P0 CLI for config inspection, workspace checks, entry inspection, space listing, entry creation, and read-only local GUI serving.
Out Of Scope
- Full import or migration compatibility with specific third-party note-taking products.
- Feature parity with third-party note-taking products or editor plugins.
- Custom executable query scripts in the initial product direction.
- Code-based schema configuration as the user-facing schema format.
- Required JSON Schema authoring files in the P0 minimal starter.
- Arbitrary expression evaluation, filters, loops, conditionals, includes, partials, or scripting inside template placeholders.
defaultin space schema fields for P0.- Publishing systems in the initial product direction.
- Assuming the current repository's
knowledge/layout is the default or only future workspace structure. - Assuming all users understand Git concepts.
- Additional configuration scopes or override layers in the MVP. P0 has one effective configuration assembled from
.forma.mdand validated configured imports. - Agent-only product capabilities. Agent and Skill flows should not be the only way to create, inspect, validate, or maintain knowledge structures.
- Local full index, SQLite index backend, filesystem watcher, or vector index in P0.
- Heavy archive, merge, provenance, or recycle-bin workflows in the MVP.
- First-class deprecate, delete, move, rename, search/query, and fix commands in the initial required P0 command set.
Open Questions
- What exact P0 starter file contents should initialize
notes,tasks,members,decisions,proposals, andguidelineswithout constraining advanced workspaces? - What exact P0 Schema DSL, semantic type, template, and view configuration syntax should be implemented first?
- When should loaders or integrations become necessary beyond declarative space configuration?
- How should Forma package or expose repository-backed knowledge so operational systems such as Choral Flows can consume it as a Git-backed knowledge source without turning Forma into a Flows backend or losing repository authorship?
- How should the product model promotion workflows from personal content to shared content?
- How should shared content be split into personal work material without losing provenance?
- What exact CLI, JSON result, and future skill interfaces are needed for Agents to check workspace health?
- What conflict and pull request workflows can be made understandable for non-software users?
- How should structured content artifacts such as JSONL event logs and SQLite projections participate in repository-backed workspaces without turning derived databases into hidden source-of-truth stores? See product/structured-artifacts-and-source-facts.
- What evidence would justify future explicit configuration or visibility scopes, and what authorization and publication contract would they require?
- Which runtime values should be available in P0, and how should custom runtime value providers be configured safely later?