Printable report
spec
Generated 2026-10-13T21:17:45.000Z
Status rollup
- Not present
- 475
- done
- 399
- draft
- 7
- in-progress
- 19
- incomplete
- 29
- partial
- 1
- pending
- 2
- todo
- 1
spec
packages/extension/src/analytical_submodule/spec.rq
this folder is the extension host adapter for `@reqlan/analytical`: VS Code wiring ( watchers, Uri helpers, IndexService ) over the shared WorkspaceIndex engine. Index ownership lives in packages / analytical. Product-surface registration lives in register-contributions.ts. Export UI lives in export_module.
import_alpha
packages/language/test/fixtures/wildcard-refs/alpha.rq
alpha idea
import_beta
packages/language/test/fixtures/wildcard-refs/alpha.rq
beta idea
other_thing
packages/language/test/fixtures/wildcard-refs/alpha.rq
not matched by import_*
import_gamma
packages/language/test/fixtures/wildcard-refs/gamma.rq
gamma idea
import_alpha
packages/packages/language/test/fixtures/wildcard-refs/alpha.rq
alpha idea
import_beta
packages/packages/language/test/fixtures/wildcard-refs/alpha.rq
beta idea
other_thing
packages/packages/language/test/fixtures/wildcard-refs/alpha.rq
not matched by import_*
import_gamma
packages/packages/language/test/fixtures/wildcard-refs/gamma.rq
gamma idea
skills
reqlan rq/ai-support.rq
rq-* skills ( chat_skill_naming, cursor_skills_install ) teach the graph, not the whole repo.
Ontology in one breath — this project as example:
- idea — named unit of intent ( `cli_package`, `skills` )
- file / ideaset — containers ( `reqlan rq/cli/cli_package.rq`; file = implicit ideaset )
- base — `.reqlan` boundary; one ideas index per base
- reference — `idea` / `wiki` / `idea` to ideas and code
- attribute / attribute_body — `@name …`; first unmarked text is the body
Prefer focused search / file context / local graph over full dumps ( ai_integration ).
- status
- done
special_attributes
reqlan rq/ai-support.rq
When creating or updating ideas, skills MUST set:
- `@status` — lifecycle ( `draft` | `pending` | `in-progress` | `done` | … )
- `@todo` — open gaps / follow-ups ( bare or with a note )
- `@tests` — quoted test paths that prove the idea ( optional `:test name` suffix )
Do not bury status, todos, or test links in body prose.
- status
- done
cli
reqlan rq/ai-support.rq
Headless twin of extension / MCP analysis: cli_package ( `reqlan` / `rq` ), same `<base>/.reqlan` index.
commands: `init` · `parse <file>` · `analyse` / `analyze` · `search <query>` · `click <target>` · `export` / `export html`.
`--json` for machines; `--cwd` / `REQLAN_WORKSPACE`; `REQLAN_INDEX_PATH` overrides index dir.
- status
- done
base
reqlan rq/bases/base.rq
A base is a container for ideas, ideasets, and files.
It forms the boundary of one ideas graph and is consumed by the CLI and the extension.
Marker: a directory is a base only when it owns a `.reqlan` folder ( application_memory ).
No bare workspace folder is treated as a base until the user creates `.reqlan` there
( create_base_onboarding ).
Aligns with base.
Discovery and registry: base-discovery.ts, base-registry.ts.
Marker path helpers: application-memory.ts.
- implementation
- base-discovery.ts, base-registry.ts, application-memory.ts
- tests
- base-discovery.test.ts:returns empty when no .reqlan exists, base-discovery.test.ts:discovers base at workspace root, base-discovery.test.ts:skips node_modules and does not treat .reqlan as a walkable base root, base-discovery.test.ts:isPathInsideOrEqual treats Windows drive paths as case-insensitive, .reqlan
base_ownership
reqlan rq/bases/base.rq
Each base holds its own ideas_index store under `<base>/.reqlan/ideas-index.sqlite`.
Path keys inside the index are relative to that base root, not the VS Code workspace root.
Store path: application-memory.ts; per-base engine: workspace-index.ts via base-registry.ts.
- implementation
- application-memory.ts, workspace-index.ts, base-registry.ts
- tests
- .reqlan, application-memory.test.ts:honours storagePath override
base_configuration
reqlan rq/bases/base.rq
Base configuration is distinct from, but related to, configuration.rq.
Optional settings live at `<base>/.reqlan/config.json` ( one config per base ).
For an `.rq` file, the applying base is the nearest ancestor that owns `.reqlan`; that base's config applies when present.
See configuration_location; resolved by reqlan-path-resolve.ts.
- implementation
- reqlan-path-resolve.ts
- tests
- config.test.ts:returns undefined when no config exists, config.test.ts:loads config from the owning base .reqlan, config.test.ts:loads config from an ancestor base, config.test.ts:nearest base config wins over farther ones, config.test.ts:owning base without config does not inherit parent, path-resolve.test.ts:loads importRoots list from nearest base config
base_configuration_provider
reqlan rq/bases/base.rq
Base-level settings live at `<base>/.reqlan/config.json`.
Extension-level settings remain VS Code configuration for the product host.
- implementation
- application-memory.ts, reqlan-path-resolve.ts, config.schema.json
base_nesting
reqlan rq/bases/base.rq
Bases may nest: any subdirectory that owns its own `.reqlan` is a child base.
Parent-base indexing includes only `.rq` files under the parent root that are **not** under
any child base root ( base-discovery.ts ownership exclusion ).
Nested bases appear as siblings in the multi-base registry; the longest-matching base root
wins for a given file path ( implied_context ).
- implementation
- base-discovery.ts, base-registry.ts
- tests
- base-discovery.test.ts:discovers nested bases and excludes child files from parent ownership, base-discovery.test.ts:baseForPath picks longest matching root
base_linking
reqlan rq/bases/base.rq
A base may have one-directional relationships with other bases.
This follows a subscription model.
Bases may be cross subscribed.
Unless linked, than bases remain isolated.
Base linking is configured in the config file in the base. reqlan directory.
- an unlinked child base should sever the contained ideas from the parent base ( i. e. the parent should just see the child as a separate base and child ideas shouldn't be visible, the indexer shouldn't crawl it. ) they should be functionally distinct
- bases, distinct from eachother in the system file tree, should be linkeable ( either one way or both ways )
- A linked child base should allow the parent base to see the child's ideas. The indexs should be linked, and the child counts etc should be included in the parents.
- A child base should always be able to link to parent base ideas.
- todo
- true
base_modes
reqlan rq/bases/base.rq
A base may be linked to
- todo
- true
base_initialisation
reqlan rq/bases/base.rq
Bases are initialised with `<base>/.reqlan/config.json`, `.reqlan/.rqignore` ( gitignore-syntax path filters; see configuration_rqignore ), `.reqlan/.gitignore` ( base_initialisation_ignore ), and a sqlite ideas index under `.reqlan` ( base_ownership ).
create-base.ts creates the `.reqlan` marker and seeds a minimal `config.json`, default `.rqignore` ( rqignore_initialisation ), and `.gitignore` when the base is new.
Full install sequencing ( extension welcome vs base seeds vs agent files ): base_installation.
base_initialisation_ignore
reqlan rq/bases/base.rq
New bases seed `<base>/.reqlan/.gitignore` so Git does not track SQLite application-memory files.
Patterns cover the ideas index ( base_ownership ), the diagnostics store ( index_diagnostics_store ), and SQLite sidecars ( `*.sqlite`, `*.sqlite-journal`, `*.sqlite-shm`, `*.sqlite-wal` ).
This file is Git ignore for `.reqlan/`. Path filters for discovery stay in `.rqignore` ( configuration_rqignore / rqignore ).
Written by create-base.ts as part of base_initialisation / base_installation.
- implementation
- create-base.ts, application-memory.ts, ignore.rs
- status
- done
- tests
- .gitignore that excludes sqlite artifacts, ignore.rs:create_base_seeds_gitignore_for_sqlite_artifacts
implied_context
reqlan rq/bases/base.rq
The **active base** for editor-adjacent surfaces is the longest-matching base root that
contains the focused file path. When no file is focused, the last selected base ( Ideas Summary
switcher / activity bar ) or the first discovered base is used.
Context, local graph, and analysers bind to the active base's index — not a merged global graph.
User / explicit pin is a pointer swap only — active_base_switch.
Core selection: base-discovery.ts ( `baseForPath` / `selectDefaultBase` ); editor pin / switch: index-service.ts.
- implementation
- base-discovery.ts, index-service.ts
- tests
- base-discovery.test.ts:baseForPath picks longest matching root, base-discovery.test.ts:selectDefaultBase prefers cwd containment
active_base_switch
reqlan rq/bases/base.rq
Changing the active base is a **pointer swap** onto a per-base `WorkspaceIndex` / store.
- Do **not** await soft-sync, hard-rebuild, or a full `.rq` walk on the switch call itself.
- Host surfaces rebind views to the newly active store ( status snapshot, tables, context panes ) immediately.
- If the selected base is not yet ready, show its readiness / progress and **schedule** the normal activate catch-up
( open if needed, then one soft sync ) fire-and-forget — same path as triggers /
indexing_trigger_open, not a special switcher rebuild.
- Idle staleness checks only touch bases that are already open; they must not reopen every discovered base
( release_when_idle ).
- Open failures stay isolated per base so one bad base cannot leave siblings stranded in `uninitialized`.
- Editor-follow must not overwrite a user pin on the same refresh that applies the selection.
- Inactive bases release SQLite artifacts when the active pointer moves away
( sqlite_artifact_lifecycle ).
Surfaces: activity bar workspace_base_picker, Ideas Summary ideas_summary_base_scope.
Implemented by index-service.ts ( `setActiveBaseId` / `scheduleBaseCatchUp` ); engine: base-registry.ts `ensureBaseReady` / `releaseArtifacts`, workspace-index.ts `ensureReady` / `deactivate`.
- implementation
- index-service.ts, base-registry.ts, workspace-index.ts, activity-bar-webview-provider.ts, ideas-summary-panel.ts, workspace_base_picker, ideas_summary_base_scope, sqlite_artifact_lifecycle
- status
- done
- tests
- base-registry-catchup.test.ts:ensureBaseReady opens and soft-syncs an uninitialized base, base-registry-catchup.test.ts:checkStaleAll heals an uninitialized base, base-registry-catchup.test.ts:deactivate returns to uninitialized so a base can be reopened, sqlite-artifact-release.test.ts:BaseRegistry releaseArtifacts closes handles but keeps descriptors
multi_base_environment
reqlan rq/bases/base.rq
Analytical features are multibase aware via base-registry.ts:
one ideas_index / `WorkspaceIndex` per base, isolated catalogs ( no cross-base idea-id collision ).
Surfaces list all discovered bases; Ideas Summary and context panes scope to the active / selected base ( active_base_switch ).
Cross-base reference resolution and merged graphs are out of scope for the first multi-base pass.
Headless ( CLI / MCP ) selects one base via open-analysis-api.ts; the editor hosts index-service.ts.
- implementation
- base-registry.ts, base-discovery.ts, index-service.ts, open-analysis-api.ts
- tests
- base-discovery.test.ts:discovers nested bases and excludes child files from parent ownership, base-discovery.test.ts:baseForPath picks longest matching root, base-discovery.test.ts:selectDefaultBase prefers cwd containment
create_base_onboarding
reqlan rq/bases/base.rq
When discovery finds **zero** bases under any VS Code workspace folder ( root or child ),
the extension prompts the user to create a reqlan base at the workspace-folder root.
Do not auto-create `.reqlan`. Command `reqlan.createBase` creates `<folder>/.reqlan/`
( empty directory is a valid marker ) via create-base.ts, then calls base-registry.ts `refresh`
so the new marker is registered and the returned base descriptor matches discovery
( refresh_rediscovers_bases ). With multiple workspace folders and no bases, prompt against the first folder.
Headless create-base helper: create-base.ts ( also used by CLI `init` ).
- implementation
- create-base.ts, index-service.ts, base-registry.ts, register-commands.ts, WorkspacePane.svelte, StatusBar.svelte
- tests
- create-base.test.ts:creates .reqlan marker and reports created, base-registry-refresh.test.ts:refresh after createBase registers the new base
refresh_rediscovers_bases
reqlan rq/bases/base.rq
Manual Refresh ( command `reqlan.refreshIndex`, activity-bar / Ideas Summary Refresh buttons )
and Clear & rebuild must **always rediscover** `.reqlan` markers under workspace roots before
soft-sync or rebuild. Do not skip discovery when bases are already registered — a new nested
or sibling base created on disk must appear after Refresh.
Discovery and registration live in base-registry.ts ( `refresh` → `rediscover` → optional
`ensureBaseReady` for the active base ). The extension adapter ( index-service.ts ) calls
that analytical API; it must not invent a parallel discovery walk.
Create Base follows the same refresh path after create-base.ts so the new marker is visible
immediately ( create_base_onboarding ).
Related: multi_base_environment, indexing_trigger_manual,
event_driven_base_access.
- implementation
- base-registry.ts, index-service.ts, register-commands.ts, activity-bar-webview-provider.ts, ideas-summary-panel.ts, WorkspacePane.svelte, IndexPanel.svelte
- status
- done
- tests
- base-registry-refresh.test.ts:refresh rediscovers a base created after an empty discovery, base-registry-refresh.test.ts:refresh rediscovers a nested base added after first discovery, base-registry-refresh.test.ts:refresh after createBase registers the new base, refresh-rediscovers-bases.test.ts:IndexService.syncWorkspace calls registry.refresh, refresh-rediscovers-bases.test.ts:IndexService.createBase calls createBase then registry.refresh, refresh-rediscovers-bases.test.ts:reqlan.refreshIndex command uses syncWorkspace
no_base_behaviour
reqlan rq/bases/base.rq
When no base is found, the extension should prompt the user to create a base at the workspace-folder root.
consideration should be made for the cli_package, the extension and the analysis_scope
The indexing should not throw errors - it should default to a global tmp index scope the workspace; or current working directory.
In the cli; an warning should be shown on first command execution if no base is found.
brand
reqlan rq/brand.rq
reqlan has a simple brand. Dark rust; and aqua blue pallete. Pink for highlights. Logo is nodular graph / crosshair
extension_brand
reqlan rq/brand.rq
The extension uses the brand logo from logo.svg.
PNG is used for marketplace, language file icon, activity bar, README, and chat participant surfaces ( Azure Marketplace rejects SVG ).
WebP is generated as a raster fallback.
file_icon
reqlan rq/brand.rq
the file icon for. rq files should use the reqlan logo.
cli_package
reqlan rq/cli/cli_package.rq
`packages/cli` ( `@reqlan/cli` ) is the Clipanion CLI published to npm as the `reqlan` ( and `rq` ) binary.
Headless commands go through the core analytical engine ( `@reqlan/analytical/core` / `reqlan-napi` ), not Langium.
Entry: main.ts via cli.js ( windows_esm_entry ).
Analysis commands reuse application_memory ( `<base>/.reqlan` ) and the analytical index so the CLI shares the ideas index with the extension and MCP.
- tests
- runtime-engine.test.ts:CLI runtime opens AnalysisApi through the core engine, language, runtime-engine.test.ts:search does not load the Langium language module, language
architecture
reqlan rq/cli/cli_package.rq
The cli should be a thin wrapper around `@reqlan/analytical/core` ( Rust engine ).
`search` / `analyse` / `export` / `init` / `parse` must not load `@reqlan/language`.
`barrel` may dynamically import the Langium barrel helper because page splits stay JS text edits
( native_bridge ).
- status
- done
windows_esm_entry
reqlan rq/cli/cli_package.rq
Node's ESM loader on Windows requires `file://` URLs for absolute dynamic `import()`.
A native path such as `C:\...\out\main.js` is read as protocol `c:` and crashes every command, including `init`.
`bin/cli.js` converts the compiled entry with `fsPathToEsmSpecifier` ( `pathToFileURL` ).
The MCP stdio entry mcp.js uses the same `pathToFileURL` conversion.
- implementation
- cli.js, esm-path.ts, mcp.js
- status
- done
- tests
- windows-esm-entry.test.ts:does not treat a Windows drive letter as a URL scheme, windows-esm-entry.test.ts:CLI bin loads the compiled entry via an ESM file URL helper, windows-esm-entry.test.ts:MCP bin converts the compiled entry with pathToFileURL
commands
reqlan rq/cli/cli_package.rq
Minimal commands:
- `parse <file>` — parse one `.rq` file via the core engine `parseReqlanSource` ( Rust `reqlan-parse` ); print diagnostics or an AST summary ( `--json` for machine output ).
- `analyse` / `analyze` — file ( `--file` ), idea ( `--idea` ), workspace completion ( default ),
local symbolic ( `--local-symbolic <file>`: outbound + same-file inbound, no index —
local_symbolic_analysis ),
or broken references ( `--broken-refs` ) via `AnalysisApi`.
`--glob` limits `--broken-refs` to a path subset of the base.
`--include-comments` adds unresolved comment_reference sites ( test_references ).
- `search <query>` — semantic search via `AnalysisApi.searchRequirements`.
Repeatable `--context <path|path#idea|name>` biases ranking by graph hop distance
( contextual_search ).
- `click <target>` — compact local context for an idea, `.rq` file, or indexed code file via `AnalysisApi.click`
( click ). No match uses search; more than one match is ranked by session distance.
Optional `--session` continues a click session. `--max-backlinks` / `--max-siblings` / `--max-outbound` / `--max-candidates` cap lists.
- `export` / `export html` — multi-file HTML site via `NativeAnalysisApi.exportHtml` ( html_export ).
`--exclude-secret` omits `*.secret.rq`.
`--exclude-ignored` omits paths matched by `.reqlan/.rqignore`.
`--url-base` mounts root-relative hrefs per html_export_url_base.
`--header-href` / `--header-label` set the topbar home link per html_export_header_link.
- `init directory` — create a new base marker ( `.reqlan` ) at the given path or cwd ( init ).
- `check` — CI wrapper around index unresolved references ( check ).
Reports broken idea, comment, file, and import references ( check_unresolved_imports ). Skips lines after comment_reference_ignore.
Repeatable `--glob <pattern>` limits the recursive scan to files that match any pattern
( check_glob_patterns ).
One `--glob` selects the same files as one path glob.
A positional file outside those patterns is checked as that file.
A positional directory outside those patterns is not walked.
`--json` / `--pipe` select machine output. Exit status is 1 when the command finds issues.
Issue order groups shared missing targets ( check_order_by_target ).
`--wildcard-zero` / `--wildcard-one` are `warn` ( default ), `error`, or `off`
( check_wildcard_zero, check_wildcard_one ).
Repeatable `--skip-target <glob>` omits issues whose missing target matches the glob
( check_skip_targets ).
`--skip-gitignored-targets` omits file-reference issues whose missing target is gitignored
( check_skip_gitignored_targets ).
- `barrel <file>` — split a large `.rq` page into one file per idea and a container import page ( barrel_page ).
- `diff <from> <to>` — compare ideas between two git revisions ( diff ).
No arguments compare pending `.rq` edits with `HEAD`, or `HEAD~1` with `HEAD` when those edits are absent.
`--verbosity` is `summary` ( default ), `references`, or `text`. `--json` prints the same rows as MCP.
Extra args from `pnpm run`: pnpm_extra_args.
watch
reqlan rq/cli/cli_package.rq
The cli should be able to watch a base and maintain the index as files change.
- todo
- true
init
reqlan rq/cli/cli_package.rq
The cli should be able to initialise a new base.
Creates `<path>/.reqlan/` ( empty directory is a valid marker ), matching create_base_onboarding.
Headless helper lives in `@reqlan/analytical` so CLI and extension share one create-base path.
- implementation
- create-base.ts, init.ts, index-service.ts
- status
- done
- tests
- create-base.test.ts:creates .reqlan marker and reports created, create-base.test.ts:is idempotent when marker already exists, windows-esm-entry.test.ts:CLI bin loads the compiled entry via an ESM file URL helper
pnpm_extra_args
reqlan rq/cli/cli_package.rq
`pnpm run <script> -- <flags>` inserts a lone `--` between the script body and the extra flags.
Clipanion treats `--` as end of options, so `reqlan check -- --skip-target glob` reads `--skip-target` as a command and fails.
The CLI drops lone `--` tokens from argv before Clipanion runs, so package-manager extra args stay flags.
Related: commands check_meta_implementation
- status
- done
- tests
- argv.test.ts:drops a lone end-of-options marker, check.test.ts:accepts skip-target after a pnpm end-of-options marker
function_parity
reqlan rq/cli/cli_package.rq
CLI shares headless function definitions with MCP and other tools through `@reqlan/analytical` `AnalysisApi`, not VS Code host APIs from extension.
On-disk index storage follows application_memory ( same `.reqlan` path as the extension ); optional override via `REQLAN_INDEX_PATH`.
- status
- done
click
reqlan rq/cli/click.rq
The click function returns compact local context for one target.
Input: an idea name, a `path#idea` ref, a `.rq` file path, or an indexed code file ( click_input, click_code_file ).
Resolution uses click_ambiguity: no match uses search; more than one match is ranked; one match uses click_output.
Optional click_max_detail flags cap how many names and bodies are listed.
Optional `sessionKey` continues a click_session. A second click on a centre already clicked in that session returns the connected content ( click_session ).
Surfaces: CLI `reqlan click` ( click.ts ), MCP `click` ( server.ts ), and native-analysis-api.ts `click`.
MCP search and retrieval use this tool only ( mcp_click_retrieval ).
Engine: click.rs on architecture / analytical_rust_port.
Related: function_parity, commands, agent_advisory, click_session, click_input, click_max_detail, click_output.
- implementation
- click.rs, click_sessions.rs, native-analysis-api.ts, click.ts, server.ts, lib.rs
- status
- done
- tests
- click.rs:click_returns_unique_idea_without_edges, click.rs:click_outbound_lists_content_refs_only, click.rs:click_accepts_file_path_as_one_file_node, click.rs:click_revisit_returns_connected_content, click.rs:click_falls_through_to_search_when_nothing_matches, click.rs:click_ranks_ambiguous_names_by_session_distance, click.test.ts:click API returns session key and unique then revisit, click.test.ts:click command emits session and unique context
click_input
reqlan rq/cli/click.rq
Accept any of:
- idea name ( trimmed optional surrounding brackets `name` )
- `path#idea` ( indexed file URI + idea name ) — this form is unique
- `.rq` file path — the file is one centre, not every idea in the file
- indexed code file path ( click_code_file )
Resolution uses click_ambiguity after the same ref normalisation as
( contextual_search / `resolve_search_context_refs` ).
When no centre matches, click uses fuzzy_search ( and file_search ) with the target as the query and returns those hits. Do not return an empty slice.
When more than one centre matches, and the click_session already has ideas, rank the matches by undirected hop distance from those ideas ( idea_graph_distance / click_input ). Nearer ranks first. Put the hop count on each candidate.
When there is no session key, or the session has no ideas yet, do not calculate hop distance. Do not print hops. Rank by name and file path. On the search path, rank by fuzzy_search score only.
When exactly one centre matches, return click_output.
Always return or create a click_session key.
- implementation
- click.rs, contextual.rs, fuzzy.rs
- status
- done
- tests
- click.rs:click_returns_unique_idea_without_edges, click.rs:click_accepts_file_path_as_one_file_node, click.rs:click_falls_through_to_search_when_nothing_matches, click.rs:click_ranks_ambiguous_names_by_session_distance, click.rs:click_omits_hops_when_session_has_no_ideas
click_ambiguity
reqlan rq/cli/click.rq
Engine function that classifies a name or target as none, unique, or ambiguous.
A name is ambiguous when more than one indexed idea or indexed file shares that exact name.
Names are unique inside one file ( idea_name ); ambiguity is across files.
`path#idea` and a full indexed path are unique when that record exists.
Click uses this function to choose the click_input path and to decide when click_output prints a file path next to a name.
Outbound wildcard_reference targets are ambiguous: print their matching paths.
Surfaces: AnalysisApi `checkNameAmbiguity` ( engine ). Click must call it. CLI / MCP exposure is not required.
- implementation
- click.rs, lib.rs, native-analysis-api.ts
- status
- done
- tests
- click.rs:check_name_ambiguity_classifies_none_unique_and_ambiguous, click.rs:click_prints_file_when_name_is_ambiguous, click.rs:click_ambiguous_code_file_basename
click_max_detail
reqlan rq/cli/click.rq
Flags that cap how many names and bodies click lists. Invalid or missing values use the default. Values less than 1 use 1.
Defaults live in `.reqlan/config.json` under `click` ( configuration_location, configuration_schema_file ). CLI and MCP flags override config.
- `maxBacklinks` / `--max-backlinks` / `click.maxBacklinks` — first n backlink names in click_output, then " + m more ".
- `maxSiblings` / `--max-siblings` / `click.maxSiblings` — first n sibling names, then " + m more ".
- `maxOutbound` / `--max-outbound` / `click.maxOutbound` — first n outbound names or paths, then " + m more ".
- `maxCandidates` / `--max-candidates` / `click.maxCandidates` — search hits and ranked ambiguous matches.
The default for each list is `click.listLimit` in defaults.json.
`maxDetail` / `--max-detail` is the old hop-depth for a neighbourhood dump. Unique click_max_detail does not use hop depth. The flag is still accepted and ignored on the unique path.
- implementation
- click.rs, click.ts, server.ts, defaults.json, config.schema.json, path_resolve.rs, reqlan-path-resolve.ts
- status
- done
- tests
- click.rs:click_caps_lists_and_reports_omitted, path_resolve.rs:click_list_limits_read_config, config.test.ts:loads click list caps from applying config, config.test.ts:schema file documents click maxSessions
click_output
reqlan rq/cli/click.rq
The result always includes `sessionKey` ( agent_advisory ).
The result does not include an `edges` list. Links are implied by the lists below.
Shape depends on click_input:
Unique ( one centre ):
- the idea ( or file ) and its content ( indexed unmarked body / summary )
- count of outbound links from that content only: idea refs and file_reference that occur in the unmarked body. Do not list refs that occur only in `@tests`, `@implementation`, or `@todo`. Do not list comment_reference code files as outbound. List names. When click_ambiguity says the name is ambiguous, print the file path with the name. File names are unquoted basenames.
- count of backlinks and the first n names ( click_max_detail ); print the file when the name is ambiguous or shared; then " + m more " for the remainder
- count of siblings ( same ideaset / file ), not the ideas named in the content, and the first n names, with file when the name is ambiguous or shared
- for a code-file centre, see click_code_file
Ambiguous ( more than one match ): ranked candidate names with file paths. Include hop distance only when the session has prior ideas. No idea bodies. Cap with `maxCandidates`.
Search ( no exact match ): fuzzy_search / file_search hits. Cap with `maxCandidates`.
Revisit: see click_session. Show content of the connected nodes, not the centre body again.
- implementation
- click.rs, types.rs, native-analysis-api.ts
- status
- done
- tests
- click.rs:click_returns_unique_idea_without_edges, click.rs:click_outbound_lists_content_refs_only, click.rs:click_prints_file_when_name_is_ambiguous, click.rs:click_caps_lists_and_reports_omitted, click.rs:click_revisit_returns_connected_content, click.test.ts:click API returns session key and unique then revisit, click.rs:click_omits_hops_when_session_has_no_ideas
click_code_file
reqlan rq/cli/click.rq
An indexed code file is a first-class click target ( index_code_files, referenced_files ).
Click accepts the same path forms as file_search ( relative path, basename when unique ).
Unique output for a code file:
- the file path ( no idea body )
- count and names of backlinks: ideas with a file_reference to this file; print the idea file when the name is ambiguous
- count and names of comment_reference targets ( `comment_link` from this file ); print the idea file when the name is ambiguous
- siblings do not apply
Data is the same indexed edges as file_related_requirements.
- implementation
- click.rs, index_code_files
- status
- done
- tests
- click.rs:click_code_file_returns_backlinks_and_comment_refs, click.rs:click_ambiguous_code_file_basename
agent_advisory
reqlan rq/cli/click.rq
Agents must pass the click_session ID ( `sessionKey` ) to the next click action.
This keeps one agent thread on the same session so a revisit can expand connected content and so ranking can use session distance.
MCP tool text states this rule and the unique / ambiguous / search paths clearly ( server.ts `click` ).
- implementation
- server.ts, click.ts, native-analysis-api.ts
- status
- done
- tests
- click.test.ts:click command emits session and unique context
click_session
reqlan rq/cli/click.rq
Click sessions live in SQLite under application_memory as `click-sessions.sqlite`
( sibling of `ideas-index.sqlite`; not deleted by ideas-index rebuild ).
Each session has a stable `sessionKey`.
Sessions are keyed against ideas. Each surfaced idea stores a fingerprint of its
name, summary, status, and tags. When that fingerprint changes, the idea may
resurface on the next click.
Record clicked centres ( unique or revisit targets ) separately from names that were only listed.
When the target is a centre already clicked in this session, return the content of the connected nodes
( outbound, backlinks, and siblings that the first click listed ), capped by click_max_detail.
Do not repeat the centre body. Do not return an empty suppressed slice.
Skip a connected body that this session already showed as content, unless its fingerprint changed.
Session cache size is click_session_limit.
Eviction uses last-touched order: when the store exceeds the limit, drop the least recently touched sessions first.
Touch the active session on every successful click.
Path helper: application-memory.ts / click_sessions.rs.
Layout: reqlan_directory_layout.
- implementation
- click_sessions.rs, click.rs, application-memory.ts, ignore.rs
- status
- done
- tests
- click.rs:click_revisit_returns_connected_content, click.rs:content_hash_change_allows_resurface, click.rs:session_cache_evicts_by_count_and_last_touched
click_session_limit
reqlan rq/cli/click.rq
Maximum stored click sessions per base is `click.maxSessions` in defaults.json.
Configure with `click.maxSessions` in `.reqlan/config.json` ( configuration_location, configuration_schema_file ).
Invalid or missing values use that default. Values below `click.minimum` use `click.minimum`.
Eviction is by session count and last-touched time ( click_session ).
Count caps for one click result are click_max_detail, not this limit.
- implementation
- defaults.json, config.schema.json, path_resolve.rs, reqlan-path-resolve.ts, click_sessions.rs, click.rs
- status
- done
- tests
- click.rs:max_sessions_reads_base_config, click.rs:session_cache_evicts_by_count_and_last_touched, config.test.ts:schema file documents click maxSessions, config.test.ts:loads click.maxSessions from applying config
diff
reqlan rq/cli/diff.rq
Compare ideas in two git snapshots.
The key is the file path plus the idea_name.
The command reads `.rq` files from git and parses each snapshot.
It does not read or write the ideas index.
Line position does not count. The same body and attributes at a different line are unchanged.
Content is the idea body plus its attributes.
Change kinds:
- created — the key exists only on the right snapshot
- deleted — the key exists only on the left snapshot
- modified — the key exists on both snapshots and the content differs
- moved — the name exists in exactly one file on each side, the paths differ, and the content is the same
The same name in more than one file on one side stays on the path-plus-name key.
A renamed idea is deleted plus created.
Unchanged ideas are omitted.
A reference-only edit stays modified.
No arguments: if any `.rq` path is staged, unstaged, or untracked and not gitignored, the left side is `HEAD` and the right side is that pending snapshot. Otherwise the left side is `HEAD~1` and the right side is `HEAD`. A non- `.rq` change does not select the pending snapshot.
One argument: that revision against `HEAD`.
Two arguments: the first revision against the second.
A target is a branch, a commit, `HEAD`, `~N` ( `HEAD~N` ), or `<rev>~N`.
The pending snapshot uses the working-tree file for an unstaged edit, the index blob when the working tree matches `HEAD`, and the working-tree file when a path is both staged and unstaged.
An untracked `.rq` file that git does not ignore is included.
If `HEAD` has no parent, the left snapshot is empty and every idea on `HEAD` is created.
A missing revision or a directory that is not a git repository is an error. Exit status is 2. A successful diff exits 0, including an empty diff.
When a side is filled by a default, the human CLI and diff_webview print a header `Comparing <from> -> <to>` before the rows. Explicit two-argument runs omit that header. `--json` and MCP stay a row array only.
Surfaces: CLI `reqlan diff` ( commands ), MCP mcp_diff, and diff.
Engine: diff.rs. Git spawns stay hidden ( consumption_silence ).
Related: architecture function_parity idea idea_reference diff_verbosity diff_cli_color
- example
- ```bash
reqlan diff A B
reqlan diff
reqlan diff HEAD~1
reqlan diff --verbosity references
reqlan diff --verbosity text
reqlan diff --json
``` - status
- done
- tests
- diff.rs:created_idea_is_listed_without_the_unchanged_idea, diff.rs:modified_body_is_modified, diff.rs:attribute_change_is_modified, diff.rs:deleted_idea_is_deleted, diff.rs:line_shift_is_not_a_change, diff.rs:one_argument_compares_with_head, diff.rs:tilde_count_matches_head_tilde, diff.rs:branch_against_head_and_two_branches, diff.rs:pending_unstaged_staged_and_layered_edits, diff.rs:clean_tree_compares_head_with_parent_and_ignores_non_rq, diff.rs:head_without_parent_lists_current_ideas_as_created, diff.rs:moved_idea_reports_both_paths, diff.rs:ambiguous_name_does_not_move, diff.rs:renamed_idea_is_deleted_and_created, diff.rs:same_revision_is_empty, diff.rs:missing_repository_and_revision_are_errors, diff.rs:implicit_targets_report_resolved_labels, diff.test.ts:lists a created idea and omits the unchanged idea, diff.test.ts:one argument matches an explicit HEAD on the right, diff.test.ts:tilde count matches HEAD~N, diff.test.ts:compares a branch with HEAD and with another branch, diff.test.ts:pending edits use the worktree, including a later unstaged layer, diff.test.ts:a clean tree compares HEAD~1 with HEAD and ignores a non-rq edit, diff.test.ts:a missing repository or revision exits 2
diff_verbosity
reqlan rq/cli/diff.rq
Three levels. The default is summary.
CLI: `--verbosity summary|references|text`, or `-v` / `-vv`.
MCP and diff_webview use the same three values.
- summary — change kind, idea name, and file. `fromFile` only for moved.
- references — summary, plus idea_reference targets added on the right and removed from the left. Order each list by name. Omit a target that is on both sides.
- text — summary, plus the body and attributes before and after. Created shows the right side. Deleted shows the left side. Modified shows both. Moved has no text change. Do not list reference names at this level.
Attributes stay inside modified. The references level does not print attribute text. The text level prints body lines, then attribute lines as `@name` / `@name value`.
`--json` omits `references` and `text` at summary. It adds `references` at references only. It adds `text` at text only.
- implementation
- diff.rs, format-diff.ts, server.ts, diff-row-model.ts
- status
- done
- tests
- diff.rs:summary_json_omits_references_and_text, diff.rs:reference_verbosity_lists_added_and_removed_names, diff.rs:text_verbosity_returns_before_and_after_body, diff.rs:text_verbosity_includes_attributes, diff.test.ts:verbosity flags and JSON omit unused fields, server.test.ts:diff returns created JSON and text bodies, diff-webview.test.ts:references lists added and removed names and hides the body, diff-webview.test.ts:text shows the before and after body
diff_cli_color
reqlan rq/cli/diff.rq
Color the human text when stdout is a terminal and `NO_COLOR` is unset.
`--color` forces color. `--no-color` forces plain text. `--json` is never colored.
Created and added lines are green. Deleted and removed lines are red. Modified is yellow. Moved is cyan.
- implementation
- format-diff.ts, diff.ts
- status
- done
- tests
- diff.test.ts:color is opt-in when stdout is not a terminal
diff_webview
reqlan rq/cli/diff.rq
Command palette title Diff Ideas, category reqlan, id `reqlan.diffIdeas` ( command_palette ).
The panel takes the same two targets and the same verbosity as diff.
Controls sit in a sticky themed strip: From, To, Detail, Diff. Inputs and the primary button use editor input and button theme tokens.
Enter in a control runs Diff. The panel runs once on open with empty targets.
Each row uses the editor git decoration colors for created, deleted, and modified, and a distinct color for moved.
A row shows kind, idea name, and path as separate fields. Moved shows both paths.
The references level lists added and removed reference names. The text level shows monospaced before and after body blocks; modified uses a two-column layout when width allows.
Empty results say there are no idea changes. Errors use validation theme colors. Diffing disables the Diff control and shows a loading status.
The panel calls the shared engine. It does not parse git output.
When a side uses a default, the panel shows the same `Comparing <from> -> <to>` header as the CLI under the strip.
- implementation
- diff-panel.ts, diff-row-model.ts, register-diff.ts, package.json
- status
- done
- tests
- diff-webview.test.ts:a created row uses the added theme token and hides the body, diff-webview.test.ts:references lists added and removed names and hides the body, diff-webview.test.ts:text shows the before and after body, diff-webview.test.ts:modified and moved map to their git decoration classes
scope
reqlan rq/codestyle/typescript.rq
TypeScript package standards for `packages/extension` ( npm `reqlan-extension` ), especially UI state.
Complements rust_mindset and state_machine_mindset.
Webview inventory: webview. Package role: extension_package.
- apply_to
- *.rq".*_pane, *.rq".*webview*, *.rq".*
ui_state_management
reqlan rq/codestyle/typescript.rq
Extension UI state is explicit, typed, and layered — not a single global store shared across host and webview.
Choose the layer by lifetime and owner:
- Host session / durable prefs live in the extension process ( `ExtensionContext`, plain modules ).
- Webview view-models live in Svelte 5 runes ( `$state` / `$derived` / `$effect` ).
- Cross-boundary traffic uses typed `postMessage` contracts only.
Prefer small state machines ( named phases, request ids, clear transitions ) over ad-hoc flags.
Related: webview_app_state, persistence_tiers, zustand_boundary, host_webview_ownership.
- apply_to
- *.rq".*_pane, *.rq".*webview*, graph.rq".graph_*
- implementation
- app.svelte.ts, app.svelte.ts, graph-ui-state.ts, table-ui-state.ts, context-session.ts
- status
- done
webview_app_state
reqlan rq/codestyle/typescript.rq
Complex webviews ( activity bar, Ideas Summary ) own a single `AppState` class in `state/app.svelte.ts`.
Fields that drive UI are Svelte 5 `$state` properties on that class; side effects and host I / O are methods.
Export one module singleton ( `export const app = new AppState()` ) and inject it via svelte_app_context.
Do not use `svelte/store` writable / readable stores for new UI, and do not put zustand inside webview code
( zustand_boundary ).
Simple panels ( export form, onboarding, index diagnostics ) may keep `$state` on the root `App.svelte`
instead of a separate AppState module when the surface is a single form / flow.
Related: table_column_filters `$derived` binding rule;
graph_ui_persistence.
- apply_to
- *.rq".*_pane, *.rq".*, webview
- implementation
- app.svelte.ts, app.svelte.ts, App.svelte, App.svelte, App.svelte
- status
- done
svelte_app_context
reqlan rq/codestyle/typescript.rq
Webview components read AppState through Svelte context helpers ( `setAppContext` / `getApp` with a `Symbol` key )
in `state/context.ts` — not by importing the singleton from deep child leaves when a context is available.
Root `App.svelte` sets context once after constructing / using `app`.
- apply_to
- *.rq".*_pane, *.rq".*
- implementation
- context.ts, context.ts
- status
- done
derived_host_bindings
reqlan rq/codestyle/typescript.rq
Components that display host-driven AppState fields must bind through Svelte 5 `$derived` / `$derived.by`
( not legacy `$:` ) so updates from the message listener re-render reliably.
Keep ephemeral widget-only UI ( open menus, local filter drafts, selection ) as component-local `$state`.
Do not mirror host payloads into a second parallel store inside the component.
- apply_to
- *.rq".table_*, *.rq".*_pane
- implementation
- IdeasetsTable.svelte, ReferenceListsPane.svelte
- status
- done
host_webview_ownership
reqlan rq/codestyle/typescript.rq
The extension host owns durable data, index / analysis queries, and VS Code APIs.
The webview owns presentation state and posts intents ( search, navigate, persist UI prefs, export ).
Host session objects ( e. g. activity-bar context session ) mutate on the host and push snapshots to the webview;
the webview must not invent a second source of truth for the same domain fields.
Typed message modules define the contract; keep request ids / error scopes on async host calls.
- apply_to
- *.rq".*webview*, *.rq".*_pane
- implementation
- activity-bar-messages.ts, messages.ts, context-session.ts, activity-bar-webview-provider.ts, ideas-summary-panel.ts
- status
- done
persistence_tiers
reqlan rq/codestyle/typescript.rq
Three persistence tiers — pick the shallowest that matches lifetime:
1. `acquireVsCodeApi().getState` / `setState` — ephemeral webview session ( pane expand / heights, active tab ).
2. `ExtensionContext.workspaceState` — durable UI prefs shared across reloads ( graph / table UI keys under
`reqlan.ideasSummary.*`, optionally per-base ). Normalize + default on read
( `normalizeGraphUiState` / table defaults ); never trust raw JSON shape.
3. `ExtensionContext.globalState` — install / user-level flags ( e. g. onboarding ), not pane view-models.
Debounce persist posts ( ~ 200 – 250 ms ) when UI controls churn. Related: webview_app_state.
- apply_to
- *.rq".*ui*, *.rq".graph_*
- implementation
- graph-ui-state.ts, table-ui-state.ts, onboarding-state.ts, vscode.ts, vscode.ts
- status
- done
postmessage_clone_safety
reqlan rq/codestyle/typescript.rq
Before `postMessage` from a Svelte webview, JSON-clone payloads ( `JSON.parse(JSON.stringify(...))` )
so `$state` proxies remain structured-clone safe. Shared helpers live in each webview's `lib/vscode.ts`.
- apply_to
- *.rq".*webview*, *.rq".*_pane
- status
- done
zustand_boundary
reqlan rq/codestyle/typescript.rq
state_machine_mindset still applies: design UI and host flows as state machines.
Zustand is no longer used anywhere: the index lifecycle FSM ( `opening` / `syncing` / `ready` / `error` ),
counts, file issues, and the document-update ring now live in Rust `WorkspaceIndexRuntime` and are read
over napi via `statusSnapshot()` ( native_bridge ); durable diagnostics persist
in `index-diagnostics.sqlite`. TypeScript keeps no parallel copy of that state.
Do not reintroduce zustand ( or Redux-like globals ) in `packages/extension/webviews/**` or the analytical
package. Extension-host TypeScript may keep plain mutable session modules when the surface is small and
message-pushed; owned lifecycle / state machines belong in the Rust runtime.
- apply_to
- *.rq".*webview*, *.rq".*_pane
- implementation
- workspace_index.rs, native-workspace-index.ts, app.svelte.ts, context-session.ts
- status
- done
imperative_view_controllers
reqlan rq/codestyle/typescript.rq
Heavy imperative widgets ( Cytoscape graph ) keep lifecycle state on a controller class
( `GraphCyController` ), not inside AppState `$state` fields.
AppState holds query / slice / loading / error and persisted UI prefs; the component holds the controller instance.
See webview_threading and
graph_loading.
- apply_to
- graph.rq".graph_*, *.rq".graph_*, *.rq".*graph*
- implementation
- graph-cy-controller.ts, app.svelte.ts
- status
- done
mission_statement
reqlan rq/constitution.rq
This project offers a structred semantic framework for supporting people working with llms to document their semantic requirements as code; and provide ergonomic consumption and definition of them.
llm_first
reqlan rq/constitution.rq
The language should be designed to be easy to use with llms.
It should be support token minimisation.
vsc_first
reqlan rq/constitution.rq
The language should be designed to be easy to use with vscode.
general_purpose
reqlan rq/constitution.rq
The language should work in any stack. And ideally, even in non-software development environments.
simplicity
reqlan rq/constitution.rq
The language should be simple to understand and use, and offer flexibility in the syntax for minimised friction and bp.
scope
reqlan rq/constitution.rq
The scope of these requirements spans the entire project, including the language itself, the developer-user tooling, and the reqlan-developer environment.
inspiration
reqlan rq/constitution.rq
This project draws upon ideas from the following fields:
- LLMS
- Software development
- Obsidian / Personal Knowledge Management systems.
- Industrial Control Engineering
- Ontology based business information systems
supply_chain
reqlan rq/constitution.rq
The supply chain for this project should be open and transparent, minimising risk and immature dependencies.
elevator_pitch
reqlan rq/constitution.rq
Build high quality, verifiable, explainable systems, quickly
Site landing: elevator_pitch_section
scope
reqlan rq/core-architecture.rq
These requirements describe the cross-package system architecture of the reqlan monorepo:
language definition, language server, ideas index, editor product, and companion tools.
They are distinct from scope, which bounds only the VS Code extension and LSP product surface.
Language concepts live in ontology.rq; syntax truth lives in syntax.rq; editor module contracts live under extension / module.
Grouped as workspace_packages, language_runtime, and product_map.
monorepo
reqlan rq/core-architecture.rq
The workspace is a pnpm monorepo ( `packages\*`, extension webviews, and `site` ) per pnpm-workspace.yaml and pnpm.
TypeScript project references build in order language → analytical → mcp → cli → extension per tsconfig.build.json.
Living requirements for the product live in this `reqlan rq` folder.
Root orchestration ( Langium generate, package builds, Cursor skill sync ) lives in package.json.
Why libraries are separate packages ( and how Changesets sees them ): package_versioning.
language_package
reqlan rq/core-architecture.rq
`packages/language` ( `@reqlan/language` ) is the canonical language definition.
It owns Langium grammars, generated AST and parser, scoped linking, validators, and LSP service providers.
Public DI entry is reqlan-module.ts via `createReqlanServices`.
Consumers: analytical_package ( native index / analysis via napi ), extension_package ( LSP ).
Published to npm as a library dependency of language_package; not Marketplace-published. See version_management and package_versioning.
analytical_package
reqlan rq/core-architecture.rq
`packages/analytical` ( `@reqlan/analytical` ) is the shared requirement graph index and analysis layer.
It owns the indexer.rq: extracts ideas and edges into a rusqlite store via the core native engine ( workspace-index.ts ), holds Zustand analytical state, and exposes analysers and an analysis API.
Headless CLI / MCP entry is `@reqlan/analytical/core` via `openAnalysisApi` ( native required; no Langium ).
Consumers: extension_package ( thin editor adapter ), mcp_package, cli_package.
Depends on language_package for the editor LSP only. Published to npm alongside cli_package; version graph role: package_versioning.
Rust engine port ( lexer / parser-for-index, indexer, search, export ): analytical_rust_port, shipped per rust_binary_distribution.
- plan
- goal
Replace the TypeScript analysis engine (parse-for-index, extract, SQLite index, search, export) with a Rust library behind the existing `createAnalysisRuntime` / `AnalysisApi` facade, shipped as per-architecture binaries and per-target VSIXes.
constraints
- Distribution: rust_binary_distribution + vsix_export — npm optional platform packages and host-targeted VSIX; website downloads and GitHub-release postinstall out of scope.
- Shared on-disk ideas_index under `<base>/.reqlan` is schema v4 rusqlite (native required; no sql.js fallback).
- The language server is language_server_rust. This analytical plan does not replace that process. Do not switch the language to tree-sitter (grammar_and_parser).
- Port the context-sensitive lexer (lexer_rust) rather than a parser-generator that cannot honour syntax.rq brace/fence rules.
- nonblocking_index and parse_budget_timeout still apply; rust_mindset and supply_chain (mature crates).
- Extension host requires the host-matching napi `.node` from the per-target VSIX (extension_host_target).
- Zustand host state, webviews, and HTML-export client JS stay TypeScript.
steps
1. Scaffold `crates/` + golden tests vs Langium (rust_crate_layout).
2. Lexer, then parser with recovery and budget (lexer_rust, parser_rust).
3. Extractor + rusqlite + incremental sync (indexer_rust).
4. Search analysers (search_rust).
5. Export snapshot + writers; keep interactive HTML JS (export_rust).
6. napi-rs per-arch host packages; CLI then MCP then extension via platform VSIX (native_bridge, cutover).
7. Publish on `analytical/v*` and ship per-target VSIXes (rust_binary_distribution, vsix_export).
open
- Language-server process: language_server_rust. CLI `parse` uses the core Rust engine. - status
- in-progress
extension_package
reqlan rq/core-architecture.rq
`packages/extension` ( npm `reqlan-extension` ) is the editor product per extension_package.
It registers `.rq` language support, TextMate grammars, starts the language client, and owns activity bar, Ideas Summary, chat, skills, and mutation hooks.
Ideas index engine lives in analytical_package / indexer.rq; the extension only hosts a thin VS Code adapter ( index-service.ts ) for watchers and UI.
Host entry: main.ts. LSP process: language_server_rust. Node fallback: main.ts.
Depends on language_package and extension_package.
Follows event_driven and state_machine_mindset for JS state;
webview UI standards in ui_state_management.
This is the one Marketplace / Open VSX shippable; see package_versioning.
mcp_package
reqlan rq/core-architecture.rq
`packages/mcp` ( `@reqlan/mcp` ) is a stdio MCP server over the analytical analysis API — no VS Code host required.
Entry: main.ts via mcp.js. Binary name `reqlan-mcp`. Used by Cursor and other MCP clients per mcp and mcp_tools.
Search and retrieval use mcp_click_retrieval ( `click` ) only.
npm `mcpName` is `io.github.littletuna4/reqlan` for MCP Registry ownership checks ( package.json ).
Published to npm with language, analytical, and CLI per package_versioning and version_management ( `mcp/v*` ).
Windows ESM entry uses `pathToFileURL` like windows_esm_entry.
- tests
- windows-esm-entry.test.ts:MCP bin converts the compiled entry with pathToFileURL, server.test.ts:MCP surface is click, check, diff, completion_status, and prompt
cli_package
reqlan rq/core-architecture.rq
`packages/cli` ( `@reqlan/cli` ) is a Clipanion CLI over the core analytical engine ( `@reqlan/analytical/core` ) for parse, analyse, search, and export.
Entry: main.ts. Binary name `reqlan` ( alias `rq` ). Published to npm with language, analytical, and MCP per package_versioning and version_management.
site_package
reqlan rq/core-architecture.rq
`site` is the marketing / docs Next. js site per site_package.
It is off the language-service and ideas-index path.
Release-driving publishable alongside extension_package; see package_versioning.
package_versioning
reqlan rq/core-architecture.rq
Separate workspace packages exist for build isolation and reuse — not because each ships to every channel.
language_package and analytical_package are leaf libraries shared by LSP, index, MCP, and CLI; they need their own package boundaries for TypeScript project refs and a single grammar / index ownership point.
Release-driving channels:
- Marketplace / Open VSX: extension_package ( `ext/v*` )
- GitHub Pages: site_package ( `site/v*` )
- npm registry: package_versioning, package_versioning, cli_package, and mcp_package ( `language/v*`, `analytical/v*`, `cli/v*`, `mcp/v*` ) via Changesets `changeset publish`
Changesets config is config.json.
language_package and analytical_package stay in the Changesets graph so a lib change can bump their versions and patch dependents via `updateInternalDependencies: "patch"` ( including the extension, CLI, and MCP ).
Extension webview folders may be private pnpm members ( e. g. `@reqlan/ideas-summary-webview` ) so Vite / Svelte can own deps; they bundle into extension media and are not Changesets publish targets. Activity-bar UI is not a separate package. json product.
Contributors record release intent with a changeset on publishable packages when user-facing behaviour changes; see version_management.
grammar_and_parser
reqlan rq/core-architecture.rq
The language server parses with `reqlan-parse` ( language_server_rust ).
Do not switch the language to tree-sitter.
Main `.rq` grammar file: reqlan.langium. Comment-token grammar for `rq:…` in non- `.rq` sources: reqlan-comment.langium.
`langium generate` still builds host AST modules and TextMate JSON per build_prepare.
The checked-in TextMate grammar paints the editor before semantic tokens.
Syntax requirements that the grammar must satisfy live in syntax.rq; conceptual units in idea, ideaset, reference, import_statement.
Host services stay in reqlan-module.ts. The language server does not load them.
language_server
reqlan rq/core-architecture.rq
The language server is the `reqlan-lsp` binary ( language_server_rust ).
The extension launches it over stdio ( main.ts ).
It parses open `.rq` buffers for definition, completion, semantic tokens, inlays, document links, and validation.
It reads the ideas index for workspace names. It does not keep a syntax tree for every file.
A Node Langium process remains only when `reqlan.languageServer.engine` is `node`, or when the binary is missing ( main.ts ).
Product expectation for LSP navigation and validation: lsp_support.
ideas_index
reqlan rq/core-architecture.rq
The ideas index is built and maintained by the indexer.rq in analytical_package.
Path: Rust parse / extract → SQLite via workspace-index.ts ( analytical_rust_port ).
Application memory: each base holds SQLite under `<base>/.reqlan/` ( shared by extension, cli_package, and mcp_package ) — see application_memory.
Multi-base: a BaseRegistry owns one workspace-index.ts per discovered base; the extension adapter routes file events to the owning base.
In the editor, index-service.ts watches `**\*.rq` and forwards changes to the owning base's workspace-index.ts; it serves UIs, commands, chat, and analysers.
The Rust language server reads the same store for catalogs, rename, and find-references ( language_server_rust ).
Headless ( MCP / CLI ) uses open-analysis-api.ts ( nearest base containing cwd when several exist ).
Capability requirements: index_ideas, index_technology, and sibling analysers in that file.
Triggers: triggers and idea_index_triggers.
base_containers
reqlan rq/core-architecture.rq
Ideas are organised in base.rq; each base holds the ideas_index store under its `.reqlan` application memory.
Discovery and nesting: base, base_nesting.
runtime_topology
reqlan rq/core-architecture.rq
The editor and the index do not share one process.
- LSP process: `reqlan-lsp` for live `.rq` editing ( language_server_rust ).
- Analytical workspace-index.ts ( extension host via index-service.ts, MCP / CLI via open-analysis-api.ts ): full-workspace graph for tables, local graph, chat, MCP.
Editor ↔ extension host: VS Code APIs and webview postMessage.
Editor ↔ LSP: vscode-languageclient over stdio.
The language server reads the ideas index directly. Host catalog notifications are optional.
Stack sketch: stack.
extension_surfaces
reqlan rq/core-architecture.rq
Product surfaces on extension_package nest under extension_domains:
- Host lifecycle: host_lifecycle
- Language surface: language_surface
- Index host: index_host ( graph-analysers.rq, editor adapter )
- Local context ( activity bar + context model ): local_context
( activity_bar, context_scope )
- Workspace summary ( Ideas Summary ): workspace_summary
( ideas_summary )
- Presentation ( shared webview + graph lib ): presentation
( webview )
- Agent surface: agent_surface
( chat_participant, skills-and-mcp.rq )
- Graph mutation: graph_mutation ( mutation-hooks.rq )
- Export surface: export_surface ( export_webview )
hierarchy_of_truth
reqlan rq/core-architecture.rq
Align with hierarchy_of_requirements:
- User request trumps these requirements; these requirements trump current implementation.
- Language concepts: ontology.rq; syntax rules: syntax.rq.
- Package seams and process topology: this file ( workspace_packages, language_runtime ).
- Editor UI and host contracts: extension_domains ( product_map ).
- Distribution and publishables: distribution.rq; internal vs shippable versioning: package_versioning.
workspace_packages
reqlan rq/core-architecture.rq
Ideaset (workspace_packages)
language_runtime
reqlan rq/core-architecture.rq
Ideaset (language_runtime)
product_map
reqlan rq/core-architecture.rq
Ideaset (product_map)
check
reqlan rq/core_analysis/check.rq
`reqlan check` should run perform the following checks:
- ensure all rq reference point to real nodes, unless rq ignored with comment_reference_ignore.
- this tests rqcomments point to real parts of the namespace, that code references exist, and that rq references exists.
- report unresolved imports: check_unresolved_imports.
- report a comment reference with invalid syntax: code_comment_syntax_errors.
- report a qualified reference whose file is not on disk: check_qualified_missing_file.
- report a qualified reference whose `.rq` file does not declare the idea: check_qualified_missing_idea.
- it should really just be a wrapper of the index and return the issues ( as a pipe, terminal output, or json ).
Issue order: check_order_by_target. Sparse wildcards: check_wildcard_sparse via flags check_wildcard_zero and check_wildcard_one. Path globs: check_glob_patterns. Skip missing targets: check_skip_targets check_skip_gitignored_targets. CLI: commands. MCP: mcp_check. CI: check_meta_implementation. Site demo: broken_links_showcase.
- implementation
- broken.rs, path_resolve.rs, rq_ignore.rs, api.rs, check.ts, format-broken-refs.ts, server.ts
- status
- done
- tests
- broken_references.rs:skips_idea_and_comment_refs_on_rq_ignore_error_lines, broken_references.rs:check_reports_missing_file_refs_and_skips_existing, broken_references.rs:check_reports_qualified_reference_to_a_missing_file, broken_references.rs:check_accepts_qualified_reference_when_the_file_exists, broken_references.rs:check_reports_qualified_reference_to_a_missing_idea, broken_references.rs:check_reports_namespace_qualified_reference_to_a_missing_idea, broken_references.rs:check_skips_qualified_missing_idea_on_rq_ignore_error, broken_references.rs:check_strips_test_name_and_line_suffix_before_file_exists, broken_references.rs:check_accepts_test_names_that_contain_colons_from_nested_rq, broken_references.rs:check_skips_same_file_idea_refs_and_reports_true_missing, broken_references.rs:check_accepts_import_root_alias_file_refs, broken_references.rs:analysis_api_lists_broken_refs_with_glob_and_comments, check.test.ts:checks files from two globs and one file outside them, check.test.ts:reports unresolved idea, comment, and file refs and exits 1, check.test.ts:reports unresolved imports and exits 1, broken_references.rs:check_reports_a_malformed_comment_reference, broken_references.rs:check_reports_missing_import_path, broken_references.rs:check_reports_missing_imported_idea, check.test.ts:exits 0 when there are no issues, check.test.ts:quotes source paths that contain spaces, check.test.ts:orders json rows by missing target, format-broken-refs.test.ts:quotes paths that contain spaces, broken_references.rs:check_orders_issues_by_missing_target, broken_references.rs:check_warns_when_a_wildcard_matches_zero_or_one_idea, server.test.ts:check returns JSON issue rows
check_glob_patterns
reqlan rq/core_analysis/check.rq
check accepts more than one `--glob` pattern.
Repeat `--glob` for each pattern.
A file is in the recursive scan when it matches any glob.
One `--glob` selects the same files as one path glob.
A reference target that matches no glob is still checked.
That target must resolve.
check_glob_patterns does not walk a directory that matches no glob.
A positional path can name a file outside the globs.
check checks that file.
A positional path that is a directory outside the globs is not walked.
An empty `--glob` value is an error.
API: `AnalysisApi.check({ pathGlobs, paths })`.
CLI: commands.
MCP: mcp_check.
Related: check
- implementation
- broken.rs, sync.rs, extract.rs, api.rs, lib.rs, native-analysis-api.ts, check.ts, server.ts
- status
- done
- tests
- broken_references.rs:check_two_globs_report_an_outside_target_and_skip_outside_directories, broken_references.rs:check_includes_an_explicit_file_outside_the_globs, broken_references.rs:check_rejects_an_empty_path_glob, broken_references.rs:analysis_api_check_honours_multiple_globs_and_extra_paths, check.test.ts:checks files from two globs and one file outside them, check.test.ts:does not recurse into a directory outside the globs, check.test.ts:rejects an empty glob, server.test.ts:check accepts one glob or a list of globs
check_order_by_target
reqlan rq/core_analysis/check.rq
check returns issues ordered by the missing reference target, not by the source file.
Rows that share the same missing idea, comment target, file path, or import target stay together so you can see every site that points at one missing thing.
Inside a target group, order by kind, then source file, then line.
JSON and pipe keep a flat list in that order. Terminal output uses one heading per missing target.
Related: check_order_by_target commands
- implementation
- broken.rs, format-broken-refs.ts, check.ts
- status
- done
- tests
- broken_references.rs:check_orders_issues_by_missing_target, check.test.ts:orders json rows by missing target, format-broken-refs.test.ts:groups rows that share a missing target under one heading
check_wildcard_sparse
reqlan rq/core_analysis/check.rq
A wildcard_reference is for many matches.
check recounts each wildcard against the full idea catalog, not the stored edges, so files that the indexer visited first still get the true match count.
How 0 - match and 1 - match rows are handled is controlled by check_wildcard_zero and check_wildcard_one ( both default `warn` ).
Ignore a site with comment_reference_ignore.
The language server already warns when a wildcard matches nothing ( wildcard_references ); it also warns when the match count is 1.
Related: check_wildcard_sparse wildcard_references
- implementation
- broken.rs, extract.rs, format-broken-refs.ts, reqlan-validator.ts
- status
- done
- tests
- broken_references.rs:check_warns_when_a_wildcard_matches_zero_or_one_idea, broken_references.rs:check_skips_sparse_wildcard_warning_on_rq_ignore_error, check.test.ts:warns on wildcards with 0 or 1 match, format-broken-refs.test.ts:marks wildcard sparse rows as warnings, wildcard-references.test.ts:warns when wildcard matches nothing, wildcard-references.test.ts:warns when wildcard matches only one idea
check_wildcard_zero
reqlan rq/core_analysis/check.rq
`check_references` flag `wildcard_zero` ( default `warn` ) controls a wildcard_reference that matches 0 ideas.
0 matches means the pattern hits nothing.
`warn` — emit the row with severity `warning` and match count 0.
`error` — emit the row with severity `error` and match count 0.
`off` — omit the row.
CLI: `--wildcard-zero <warn|error|off>` ( commands ).
API: `AnalysisApi.check({ wildcardZero })`.
Related: check check_wildcard_sparse check_wildcard_one
- implementation
- broken.rs, api.rs, check.ts, native-analysis-api.ts
- status
- done
- tests
- broken_references.rs:check_warns_when_a_wildcard_matches_zero_or_one_idea, broken_references.rs:check_wildcard_zero_flag_off_omits_empty_match, broken_references.rs:check_wildcard_zero_flag_error_sets_severity, check.test.ts:warns on wildcards with 0 or 1 match, check.test.ts:honours wildcard-zero and wildcard-one handling flags
check_wildcard_one
reqlan rq/core_analysis/check.rq
`check_references` flag `wildcard_one` ( default `warn` ) controls a wildcard_reference that matches exactly 1 idea.
1 match means the pattern is too narrow — use a concrete reference instead.
`warn` — emit the row with severity `warning` and match count 1.
`error` — emit the row with severity `error` and match count 1.
`off` — omit the row.
CLI: `--wildcard-one <warn|error|off>` ( commands ).
API: `AnalysisApi.check({ wildcardOne })`.
Related: check check_wildcard_sparse check_wildcard_zero wildcard_references
- implementation
- broken.rs, api.rs, check.ts, native-analysis-api.ts
- status
- done
- tests
- broken_references.rs:check_warns_when_a_wildcard_matches_zero_or_one_idea, broken_references.rs:check_wildcard_one_flag_off_omits_singleton_match, broken_references.rs:check_wildcard_one_flag_error_sets_severity, check.test.ts:warns on wildcards with 0 or 1 match, check.test.ts:honours wildcard-zero and wildcard-one handling flags, wildcard-references.test.ts:warns when wildcard matches only one idea
check_skip_targets
reqlan rq/core_analysis/check.rq
check omits an issue when the missing reference target matches a skip glob.
The analyser function `check_references` takes `skip_targets`: a list of globs.
Match uses the same path glob rules as `--glob`. Match is against the issue `label` ( the missing target ), not the source file.
An empty skip glob has no effect.
Use this when a referenced file is not in git and you name the skip glob.
For all Git ignore rules, use check_skip_gitignored_targets.
CLI: repeatable `--skip-target <glob>` ( commands ).
API: `AnalysisApi.check({ skipTargets })`.
Related: check_skip_targets check_skip_targets check_meta_implementation
- implementation
- broken.rs, api.rs, lib.rs, native-analysis-api.ts, check.ts
- status
- done
- tests
- broken_references.rs:check_skips_targets_that_match_skip_globs, broken_references.rs:path_glob_matches_cursor_skip_glob, broken_references.rs:analysis_api_check_honours_skip_targets, check.test.ts:honours skip-target globs
check_skip_gitignored_targets
reqlan rq/core_analysis/check.rq
check omits a file reference issue when Git ignore rules ignore the missing target.
The analyser function `check_references` takes `skip_gitignored_targets` ( default false ).
Match uses the workspace .gitignore and nested `.gitignore` files on the target path.
Match uses the resolved path from the workspace root, not the authored path in the source file.
Idea references, comment references, and missing imported idea names stay in the issue list.
Missing import paths follow the same skip as file references ( check_unresolved_imports ).
Use this when a referenced file is build output or editor config that git does not store.
Examples: `.cursor/` for mcp, and `packages/extension/media/webviews/` for installation_event.
CLI: `--skip-gitignored-targets` ( commands ).
API: `AnalysisApi.check({ skipGitignoredTargets })`.
CI: ci.yml and azure-pipelines.yml pass `--skip-gitignored-targets` because a CI checkout does not contain gitignored files ( check_meta_implementation ).
Related: check_skip_gitignored_targets check_skip_targets check_skip_gitignored_targets check_skip_gitignored_targets
- implementation
- broken.rs, ignore.rs, api.rs, lib.rs, native-analysis-api.ts, check.ts, ci.yml, azure-pipelines.yml
- status
- done
- tests
- broken_references.rs:check_skips_gitignored_file_targets, ignore.rs:workspace_gitignore_matches_root_and_nested_rules, broken_references.rs:analysis_api_check_honours_skip_gitignored_targets, check.test.ts:honours skip-gitignored-targets, release-ci-gate.test.ts:CI check skips gitignored targets, broken_references.rs:check_skips_gitignored_import_paths
check_qualified_missing_file
reqlan rq/core_analysis/check.rq
A qualified reference names a file and an idea. Example: `non-existentfile.ts".term`.
check reports an error when that file is not on disk.
The issue kind is `file_reference`. The label is the resolved file path.
A qualified reference to a file that exists is not this error.
A same-file idea reference is not this error.
The editor already underlines this target.
Related: check_qualified_missing_file check_qualified_missing_idea reference_file unresolved_reference_diagnostics
- implementation
- broken.rs
- status
- done
- tests
- broken_references.rs:check_reports_qualified_reference_to_a_missing_file, broken_references.rs:check_accepts_qualified_reference_when_the_file_exists
check_qualified_missing_idea
reqlan rq/core_analysis/check.rq
A qualified reference names a file and an idea. Example: `graph-analysers.rq".not_an_idea`.
The same rule applies to a namespace alias: `idea` ( import_namespace ).
check reports an error when that file is an `.rq` file, the file does not declare the idea, and the file does not bind that name as an import alias.
The issue kind is `references`. The label is the missing idea name.
A path with no extension means `.rq` first ( implicit_file_extension ).
A qualified reference to an idea that the `.rq` file declares is not this error.
A qualified reference to an import alias bound in that file is not this error.
A namespace import binds its `as` name.
A from-import or qualified import binds its `as` name, or the idea name when `as` is absent.
A from-import of an import alias stays check_unresolved_imports. The alias is not an idea.
A qualified reference to a code file is not this error. That form uses check_qualified_missing_file.
A missing file stays check_qualified_missing_idea. check_qualified_missing_idea does not also report a missing idea for that file.
comment_reference_ignore suppresses this error.
Related: check check_qualified_missing_file reference_qualified
- implementation
- broken.rs, ast.rs, analysis.rs, session.rs, reqlan-neighbor-parse.ts, reqlan-outbound-presentation.ts
- status
- done
- tests
- broken_references.rs:check_reports_qualified_reference_to_a_missing_idea, broken_references.rs:check_reports_namespace_qualified_reference_to_a_missing_idea, broken_references.rs:check_skips_qualified_missing_idea_on_rq_ignore_error, broken_references.rs:check_accepts_qualified_reference_when_the_file_exists, broken_references.rs:check_reports_qualified_reference_to_a_missing_file, golden_corpus.rs:qualified_reference_to_an_import_alias_is_not_a_missing_idea, parity.rs:golden_corpus_import_alias_is_not_an_unresolved_idea
check_unresolved_imports
reqlan rq/core_analysis/check.rq
check reports an error when an import does not resolve.
A missing import path is an error. A named imported idea that is not in the target file is an error.
Do not report imported idea names when the path is missing.
An existing folder is a valid import path ( import_folder_targets ).
A remote URL is not a missing path.
Import paths with no extension mean `.rq` first ( implicit_file_extension ).
Ignore a site with comment_reference_ignore.
Issue kind is `import`. The `label` is the missing path or the missing idea name.
Forms: import_from, import_namespace, import_qualified.
Editor underline: import_does_not_exist_error.
check_skip_targets matches that label. check_skip_gitignored_targets omits a missing import path that Git ignore rules ignore.
Related: check_unresolved_imports check_order_by_target check_unresolved_imports
- status
- done
- tests
- broken_references.rs:check_reports_missing_import_path, broken_references.rs:check_reports_missing_imported_idea, broken_references.rs:check_accepts_resolved_imports, broken_references.rs:check_skips_import_on_rq_ignore_error, broken_references.rs:check_accepts_folder_and_implicit_extension_imports, broken_references.rs:check_skips_remote_import_urls, broken_references.rs:check_skips_gitignored_import_paths, check.test.ts:reports unresolved imports and exits 1
code_comment_syntax_errors
reqlan rq/core_analysis/check.rq
A comment reference uses `rq:idea` or `rq:idea`.
A path string uses double quotes or single quotes.
A qualified reference may use dotted idea names after the path.
Line comments use `//` and `#`.
The same forms apply in every comment span that the indexer reads.
check reads each comment reference in a non- `.rq` source file.
A comment reference with invalid syntax is a syntax error.
code_comment_syntax_errors reports the syntax error.
The issue kind is `comment_syntax`.
The issue label is the error reason and the comment reference text.
The issue severity is `error`.
A valid comment reference stays a comment_reference site.
An unresolved valid target stays a `comment_link` issue.
A source file that contains only a syntax error stays in the code index.
comment_reference_ignore suppresses the syntax error on the next line.
Related: check references_in_functional_code_comments
- implementation
- comment.rs, broken.rs, sync.rs, check.ts
- status
- done
- tests
- comment.rs:reports_a_malformed_comment_reference, comment.rs:reports_an_unclosed_comment_reference, comment.rs:keeps_a_quoted_bracket_inside_a_qualified_comment_reference, comment.rs:ignores_malformed_rq_inside_strings_and_raw_strings, broken_references.rs:check_reports_a_malformed_comment_reference, broken_references.rs:check_skips_comment_syntax_on_rq_ignore_error
check_meta_implementation
reqlan rq/core_analysis/check.rq
check is a step in the sequential GitHub CI job after one workspace build.
Pull requests use ci.yml.
Main uses the same workflow through release.yml ( ci_gate ).
The job installs workspace packages once ( `pnpm install --frozen-lockfile` ), asserts `@reqlan/*` resolve under `packages/` ( assert-workspace-reqlan.mjs ), compiles crates and TypeScript, then runs crate tests, `node packages/cli/bin/cli.js check`, and JS / TS tests against that build.
Do not install `@reqlan/cli` or other `@reqlan/*` packages from npm. Platform natives in this workspace come from `packages/analytical-native/` via `packageExtensions` in pnpm-workspace.yaml, not from the registry. Do not call a global `reqlan` binary. Do not run a second install before check.
GitHub and Azure pass `--skip-gitignored-targets` because gitignored files are not in a CI checkout ( check_skip_gitignored_targets ).
Azure uses the same workspace CLI after its package build on `ext/v*` tags.
Related: check_meta_implementation check_skip_targets check_meta_implementation ci_gate
- implementation
- ci.yml, release.yml, azure-pipelines.yml, package.json, assert-workspace-reqlan.mjs
- status
- done
- tests
- release-ci-gate.test.ts, release-ci-gate.test.ts:release calls sequential CI before versioning, release-ci-gate.test.ts:CI is one sequential pull-request job, release-ci-gate.test.ts:one build is reused by crate tests, check, and package tests, release-ci-gate.test.ts:reference check uses workspace packages not npm, release-ci-gate.test.ts:TypeScript compile generates Langium sources first, release-ci-gate.test.ts:CI check skips gitignored targets
analysis_scope
reqlan rq/core_analysis/core.rq
`@reqlan/analytical` — shared index + analysis API.
Hosts: CLI, extension, MCP.
Native rewrite: analytical_rust_port.
parse index search export analysers runtime
parse
reqlan rq/core_analysis/core.rq
Lex + parse `.rq` for the index path ( not LSP ).
parser_lexer.rq → extract in index.
index
reqlan rq/core_analysis/core.rq
Ideas / edges → SQLite ( `<base>/.reqlan` ).
index
search
reqlan rq/core_analysis/core.rq
Rank ideas: fuzzy, contextual, semantic.
search
export
reqlan rq/core_analysis/core.rq
Snapshot → html / md / json / csv.
export_pipeline html_export
analysers
reqlan rq/core_analysis/core.rq
Queries over index: list, file-related, local graph, completion, deprecation, git dates, test_references.
graph-analysers.rq
runtime
reqlan rq/core_analysis/core.rq
Headless facade: `createAnalysisRuntime` / `AnalysisApi`.
analysis_runtime
test_references
reqlan rq/core_analysis/core.rq
The indexer lists broken references in a index base.
A broken reference is an unresolved idea or wildcard reference.
You can give an optional path glob so that the list covers only a subset of the base.
You can optionally include unresolved comment_reference sites.
The function is in the core analysis module. The CLI exposes it on commands ( `analyse --broken-refs` ).
Related: analysers runtime index_code_files comment_reference_resolution_error
- implementation
- broken.rs, api.rs, analyse.ts
- status
- done
- tests
- broken_references.rs:lists_broken_idea_references_and_filters_by_glob, broken_references.rs:optionally_includes_broken_comment_references, broken_references.rs:analysis_api_lists_broken_refs_with_glob_and_comments, broken-references.test.ts:lists broken idea refs and optional comment refs with a path glob
consumption_silence
reqlan rq/core_analysis/core.rq
Hosts that consume the native core ( and helper CLI tools such as `git` / `node` )
must not open a visible console window.
On Windows, a GUI editor host that spawns a console-subsystem process without
`CREATE_NO_WINDOW` / `windowsHide` flashes a CLI window.
Git-dates fill in the core engine and Activity Bar git history were the
repeating flashes after `.rq` change; the language-server Node probe can flash once
at start on old hosts.
Index parse itself stays in-process ( napi `.node` / `.dll` ) and does not spawn a console.
Related: git_dates,
git_dates_background_indexing,
git_dates_rate_cap,
git_context,
git_information_capture.
- implementation
- git_dates.rs, hidden-exec-file.ts, git-context.ts, language-server-runtime.ts, register-git-dates-background.ts
- status
- done
- tests
- git_dates.rs:create_no_window_matches_win32_flag, hidden-exec-file.test.ts, git-context.test.ts:git CLI spawns hide the Windows console, language-server-runtime.test.ts
check
reqlan rq/core_analysis/core.rq
reqlan check is a analysis tool surfaced by the cli. Intended for use in CI.
see check check_order_by_target check_wildcard_sparse check_wildcard_zero check_wildcard_one check_skip_targets check_skip_gitignored_targets check_meta_implementation
modules
reqlan rq/core_analysis/core.rq
Ideaset (modules)
export_pipeline
reqlan rq/core_analysis/export.rq
`@reqlan/analytical` owns export execution for every format.
Shared contract: `ExportRequest` / progress callbacks / snapshot build, then format writers.
Hosts ( extension webview, CLI ) assemble an `ExportRequest` and call `NativeAnalysisApi.exportHtml` / `exportMarkdown` / `exportJson` / `exportCsv` — they do not reimplement writers.
Formats: html_export, markdown_export, json_export, csv_export, pdf_export.
Progress phases ( snapshot, then write completed / total ) are reported to hosts for loading UI.
Consumed under analysis_scope.
Rust port of snapshot + writers: export_rust.
- implementation
- native-analysis-api.ts, api.rs, snapshot.rs, types.ts
- status
- done
- tests
- json_export.rs:json_export_lists_persisted_ideas
markdown_export
reqlan rq/core_analysis/export.rq
Markdown export writes a `README.md` index for the selected base ( counts, status / tag rollups, idea list, file list ) and optional per-idea `.md` pages under `ideas/` with attributes and inbound / outbound references as relative markdown links.
When per-idea pages are disabled, idea bodies are inlined in the README.
Shared base / scope / output / name and file filters apply; HTML-only page families ( graph, clusters, attributes, print ) are omitted.
Pipeline: `exportMarkdown` / `writeMarkdownExport` using the same snapshot builder as HTML ( export_pipeline ).
Extension UI host: export.rq".export_webview.
- implementation
- export-markdown.ts, write-markdown-export.ts, native-analysis-api.ts
- status
- done
json_export
reqlan rq/core_analysis/export.rq
JSON export writes `export.json` for the selected base: ideas ( with attributes and reference lists ), files, clusters, attributes, and status / tag rollups — suitable for tooling and AI consumption.
Shared base / scope / output / name and file filters apply.
Pipeline: `exportJson` / `writeJsonExport` ( export_pipeline ).
Extension UI host: export.rq".export_webview.
- implementation
- export-json.ts, write-json-export.ts, native-analysis-api.ts
- status
- done
- tests
- export-json-csv.test.ts, json_export.rs:json_export_lists_persisted_ideas
csv_export
reqlan rq/core_analysis/export.rq
CSV export writes `ideas.csv` with tags and non-status / tag attributes flattened into columns ( `attr:<key>` ), plus `references.csv` for inbound / outbound / unresolved edges.
Shared base / scope / output / name and file filters apply.
Pipeline: `exportCsv` / `writeCsvExport` ( export_pipeline ).
Extension UI host: export.rq".export_webview.
- implementation
- export-csv.ts, write-csv-export.ts, native-analysis-api.ts
- status
- done
pdf_export
reqlan rq/core_analysis/export.rq
PDF export prepares a print-oriented HTML report from the selected base so the user can Print → Save as PDF in the browser.
Direct PDF binary rendering is not required yet; preserve links in the printable HTML ( html_export_printable_pages ).
PDF-specific options include file filters and print entry filename; shared base / scope / output / name apply.
Extension UI host: export.rq".export_webview ( not a separate QuickPick chain ).
- implementation
- html.rs, mod.rs, types.rs, native-analysis-api.ts
- status
- partial
html_export
reqlan rq/core_analysis/html_export.rq
`@reqlan/analytical` builds documentation as HTML from the requirement graph ( export_pipeline, analysis_scope ).
Html export should render ideas, attributes, references, and navigable structure suitable for sharing.
Pipeline: `NativeAnalysisApi.exportHtml` / `AnalysisRuntime.export` → `reqlan-export` snapshot ( `build_export_snapshot` ) → multi-file static site ( `write_html_export` ). Single-file mode remains optional via html_export_runtime_modes.
Interactive graph / search JS stays bundled static assets ( html_export_graph_layout ), not a second writer ( export_rust ).
Thin hosts: extension UI ( export.rq".export_webview, html-export.rq".html_export_form, export.rq".export_html ) and CLI ( `reqlan export` / commands ).
Export is scoped to a selected base ( not a merged multi-base workspace graph ).
html_export_multi_file
html_export_internal_links
html_export_idea_tooltips
html_export_layout_cards
html_export_heading_tooltips
html_export_table_columns
html_export_search
html_export_list_views
html_export_overview_links
html_export_idea_pages
html_export_file_pages
html_export_code_reference_pages
html_export_cluster_pages
html_export_graph_page
html_export_attributes_index
html_export_attribute_pages
html_export_printable_pages
html_export_print_idea_cards
html_export_print_body_whitespace
html_export_print_in_page_anchors
html_export_print_all_attributes
html_export_print_button
html_export_print_order_by
html_export_runtime_modes
html_export_scrollable_lists
html_export_header_link
html_export_url_base
html_export_katz_column
- implementation
- html.rs, mod.rs, snapshot.rs, types.rs, api.rs, native-analysis-api.ts
- status
- done
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets, html_export.rs:workspace_graph_includes_every_idea_when_max_graph_nodes_is_below_count, export.rs:html_export_honours_graph_page_url_base_and_header_link, export-html.test.ts, export-html-native.test.ts
html_export_multi_file
reqlan rq/core_analysis/html_export.rq
Html export should generate a multi-file static site rather than a single document.
The export should include page families for overview, ideas, files, code files, clusters, attributes, graph, data, and print-focused pages.
html_export_internal_links
reqlan rq/core_analysis/html_export.rq
Every exported idea should have a stable html page path and stable in-page anchors.
References, breadcrumbs, search results, graph nodes, cluster members, attribute listings, file listings, and code-file listings should link to html pages rather than only showing text labels.
Overview status / tag rollups and list-table facet cells follow html_export_overview_links.
On the printable report, same-page idea links use those in-page anchors per html_export_print_in_page_anchors.
Graph node links must follow html_export_graph_links.
When html_export_url_base is set, those same links must be root-relative under the mount prefix so static hosts resolve them with or without a trailing slash.
A link `attribute` opens that attribute on the idea page. See attribute_namespacing.
A link to an idea shows that idea's body in a tooltip per html_export_idea_tooltips.
html_export_idea_tooltips
reqlan rq/core_analysis/html_export.rq
A link to an idea must show a tooltip when the pointer or keyboard focus rests on the link.
The tooltip must show the idea name, the source file, and the idea body text.
The tooltip must show the status when the idea has a status.
The tooltip must be a styled panel. The tooltip must not use the browser title text.
The tooltip must stay inside the viewport.
An unresolved reference must not show an idea tooltip.
Section and card heading tips follow html_export_heading_tooltips.
- implementation
- html_utils.rs, mod.rs, app.js, styles.css
- status
- done
- tests
- html_export.rs:idea_links_show_content_tooltips
html_export_layout_cards
reqlan rq/core_analysis/html_export.rq
In interactive runtime mode, detail-page panels ( panel, table-shell, graph-shell ) and entity-card tiles are drag-reorderable within their layout group and collapsible.
In interactive mode, cards that are direct children of a page layout group and use panel, table-shell, or graph-shell chrome are width-resizable by column span.
Entity-card tiles inside an entity-list layout group are drag-reorderable and collapsible, but they are not width-resizable.
Column hide and column width on tables stay separate from card width.
Width-resizable cards sit in a responsive multi-column grid and snap to column spans so a card can take one column, several columns, or the full row.
Double-click on the card width handle fills the row. A second double-click restores the last non-full span. Collapsed cards ignore fill.
Narrow viewports collapse spans so cards stack without horizontal overflow.
The full card header is the drag handle. Links, buttons, and inputs in the header still activate on click.
The collapse caret stays hidden until the card is hovered or has focus within.
Collapse hides the card body and shrinks the card chrome so the layout does not keep empty body space.
Card-width and header drag must not lose control to text selection: pointer capture, select lock, and preventDefault on resize pointerdown.
Order, collapse, column-span, and fill-restore state persist in localStorage for that page path.
Document and print runtime modes keep a static layout with no rearrange, resize, or collapse behaviour.
Printable-report idea cards stay outside this idea ( html_export_print_idea_cards, html_export_print_order_by ).
Table column chrome follows html_export_table_columns.
Cross-refs html_export_runtime_modes, html_export_heading_tooltips.
- implementation
- layout.rs, mod.rs, app.js, styles.css
- status
- done
- tests
- html_export.rs:interactive_layout_cards_are_reorderable_collapsible_with_heading_tips
html_export_table_columns
reqlan rq/core_analysis/html_export.rq
In interactive runtime mode, tables inside layout cards let the user hide and resize columns.
An eye control on each column header toggles that column. The eye shows when the header cell is hovered or focused.
A column-selector control in the table card header opens a multiselect panel with search, select all, clear, and shift-click range selection.
Column resize must not lose control to text selection: pointer capture, select lock, and a resize handle above selectable header text.
Hidden columns and column widths persist in localStorage for that page path and table.
Document and print runtime modes keep all columns visible at default widths with no column chrome.
Cross-refs html_export_layout_cards, html_export_list_views.
- implementation
- app.js, styles.css
- status
- done
- tests
- html_export.rs:interactive_layout_cards_are_reorderable_collapsible_with_heading_tips, html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_heading_tooltips
reqlan rq/core_analysis/html_export.rq
Section headings on layout panels show a short descriptive tip via the styled tooltip panel when pointer or keyboard focus rests on the heading.
Entity-card title headings tip with that card's short summary text.
Idea title headings tip with the idea summary when present.
Heading tips must not use the browser title text.
Reuses the tooltip surface from html_export_idea_tooltips.
Cross-refs html_export_layout_cards.
- implementation
- layout.rs, app.js, styles.css
- status
- done
- tests
- html_export.rs:interactive_layout_cards_are_reorderable_collapsible_with_heading_tips
html_export_search
reqlan rq/core_analysis/html_export.rq
The interactive html export should provide a global search bar and page-local search bars.
Search should work offline from generated data bundled with the export.
Attribute keys and values should be searchable alongside ideas, files, code files, and clusters.
html_export_list_views
reqlan rq/core_analysis/html_export.rq
Html export should provide searchable list views for ideas, files, code files, references, clusters, and attributes.
List views should preserve the usability of the current ideas summary tables with counts, sorting, filters, and quick navigation.
Every interactive table column should be sortable by header click and filterable with a per-column filter, in addition to any page-level search bar.
Navigable facet cells in those tables ( status, tags, paths, attribute values, cluster labels / kinds ) should be links to the matching detail page or to a list page with the matching column filter applied via html_export_overview_links.
Long lists that sit above other page content follow html_export_scrollable_lists.
The ideas index count columns follow html_export_ideas_ref_columns.
Column hide, resize, and selector chrome follow html_export_table_columns.
html_export_ideas_ref_columns
html_export_list_views
html_export_attributes_index
html_export_file_pages
html_export_code_reference_pages
html_export_scrollable_lists
html_export_list_views
- implementation
- mod.rs, html_utils.rs, app.js
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets, html_export.rs:ideas_index_splits_inbound_and_outbound_counts
html_export_ideas_ref_columns
reqlan rq/core_analysis/html_export.rq
The ideas index table shows inbound reference counts and outbound reference counts in two columns.
The first count column is In. The second count column is Out.
Each cell shows one integer.
Each column has its own header sort and column filter.
Filter keys are `in` and `out`.
- implementation
- mod.rs, styles.css
- status
- done
- tests
- html_export.rs:ideas_index_splits_inbound_and_outbound_counts
html_export_katz_column
reqlan rq/core_analysis/html_export.rq
HTML export shows the inbound Katz score ( katz_centrality ) for each idea.
The ideas index adds a Katz column after Out.
File idea tables, code-file idea tables, cluster member tables, and attribute idea tables add a Katz column.
The printable file sheet, code-file sheet, and cluster sheet add the same column.
The idea page and the printable idea sheet show the same score as a metric.
The cell text uses 3 decimal places. The sort value is the full score.
The filter key is `katz`.
File, cluster, and attribute index tables do not show this column.
- implementation
- snapshot.rs, types.rs, mod.rs
- status
- done
- tests
- html_export.rs:idea_tables_show_a_katz_column
html_export_overview_links
reqlan rq/core_analysis/html_export.rq
The interactive overview page status rollup, tags rollup, and highlighted clusters must be interactive navigation, not plain labels.
Status and tag rollup entries should open the matching status / tag cluster page when html_export_cluster_pages is enabled; otherwise they should open the ideas list with the Status or Tags column filter seeded from the rollup key.
Highlighted clusters should open the matching cluster page ( or the clusters index when cluster pages are disabled ).
List pages must honour URL query parameters that seed per-column filters ( for example `ideas.html?status=todo` or `ideas.html?tags=export` ) so overview and in-table facet links land with the filter already applied.
Query keys match stable `data-filter-key` values on table headers; filter values use the same display labels as the rollup ( including Not present / Empty ).
Cross-refs html_export_list_views, html_export_cluster_pages, html_export_internal_links.
- implementation
- mod.rs, html_utils.rs, app.js
- status
- done
- tests
- html_export.rs:overview_status_and_tag_rollups_link_with_filters
html_export_idea_pages
reqlan rq/core_analysis/html_export.rq
Html export should generate a dedicated page per idea.
Idea pages should include summary, attributes, inbound references, outbound references, nearby context, and links to related ideas, files, clusters, graph views, and printable forms.
Status and tags are nullable attributes: render them only when present.
html_export_file_pages
reqlan rq/core_analysis/html_export.rq
Html export should generate dedicated pages for reqlan source files that host ideas in the export scope.
File pages should list hosted ideas, related clusters, and a local graph view when available.
Emission defaults on and is controllable via includeFilePages so page families can be flagged in or out without changing the export pipeline shape.
Graph nodes and idea source-file links for hosting files should resolve to these pages when enabled.
- implementation
- types.rs, snapshot.rs, mod.rs, html.rs
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_code_reference_pages
reqlan rq/core_analysis/html_export.rq
Html export should generate dedicated pages for outbound file_reference targets and inbound comment_link code files that are not idea-hosting reqlan files already covered by html_export_file_pages.
Code-file pages should list referencing ideas and reference labels, and participate in search and navigation.
Emission defaults on and is controllable via includeCodeFilePages so this page family can be flagged in or out later.
Outbound reference path cells and graph external file nodes should link to these pages when enabled.
Comment-linked files: index_code_files.
- implementation
- types.rs, snapshot.rs, mod.rs, html_utils.rs, html.rs
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_cluster_pages
reqlan rq/core_analysis/html_export.rq
Html export should support cluster pages that group related ideas.
Deterministic clusters should at least include file, folder, tag, and status groupings.
Optional computed clusters should use graph or semantic analysis when available without making export correctness depend on them.
html_export_attributes_index
reqlan rq/core_analysis/html_export.rq
Html export should provide a searchable attributes index page listing every attribute key used in the export scope.
Each attribute entry should summarize distinct values and idea counts, and link to the dedicated attribute page when html_export_attribute_pages is enabled.
- implementation
- types.rs, snapshot.rs, mod.rs, html.rs
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_attribute_pages
reqlan rq/core_analysis/html_export.rq
Html export should generate a dedicated page per attribute key used in the export scope.
Attribute pages should show a distribution of distinct values ( counts and share of ideas ), and a searchable full list of ideas that declare the attribute with their values for that key.
Emission defaults on and is controllable via includeAttributePages so this page family can be flagged in or out without changing the export pipeline shape.
The attributes index, idea attribute tables, and search results should link to these pages when enabled.
- implementation
- types.rs, snapshot.rs, mod.rs, html.rs
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_graph_page
reqlan rq/core_analysis/html_export.rq
Html export should provide an interactive graph page with search, filters, and links back into idea and cluster pages.
The graph should support scoped views for workspace, file, cluster, and idea contexts.
The workspace graph page must include every idea in the export scope — blocks, oneliners, and ideasets — and must not apply the interactive Ideas Summary GRAPH_MAX_NODES budget.
Ideasets are visible by default with a Hide ideasets / Show ideasets toggle, matching the external-file visibility control
( explicit AST ideasets only — distinct from hosting-file treatment ).
Hosting `.rq` files ( implicit ideasets ) use a Files `<select>` — hidden / compound / linked —
with option tooltips, per file_treatment_toggle
( parity with Ideas Summary ). Compound mode draws hittable / draggable bounding boxes with clickable titles;
linked mode adds synthetic ideaset nodes that navigate via `hostFilePageUrl` / `pageUrl`.
Wildcard fan-out edges ( `wildcard_reference` ) are visible by default with a " Wildcard refs " chip
( same label / default as Ideas Summary ); turning it off client-filters those edges and draws them dotted when on —
see wildcard_refs_toggle and
webview_export_graph_parity.
Status and tag filters are multi-select and distinguish graph_status_tag_filters.
Per-idea, per-file, and per-cluster neighbourhood graphs may still use a capped budget for focused pages.
html_export_graph_links
html_export_graph_layout
html_export_graph_animation
html_export_graph_background_load
html_export_graph_subject
html_export_graph_labels
html_export_graph_label_modes
html_export_graph_label_auto
html_export_graph_interaction
html_export_graph_metadata
- implementation
- snapshot.rs, mod.rs, app.js, api.rs
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets, html_export.rs:workspace_graph_includes_every_idea_when_max_graph_nodes_is_below_count, html_export.rs:html_export_workspace_graph_includes_wildcard_refs_chip_and_edges, export.rs:html_export_honours_graph_page_url_base_and_header_link
html_export_graph_links
reqlan rq/core_analysis/html_export.rq
Graph node hrefs must resolve to idea pages from every export page depth, including nested idea, file, and cluster pages.
Node urls should be export-root-relative so path segments such as ideas / are not dropped when resolving from nested pages.
When html_export_url_base is set, runtime resolution of those urls must honour the mount prefix ( same contract as page and asset hrefs ).
External file nodes should resolve to html_export_file_pages or html_export_code_reference_pages when those page families are enabled.
Hosting-file linked nodes ( file_treatment_toggle linked mode ) prefer `hostFilePageUrl` stamped during graph URL enrichment
( file / code-file page for the idea's `fileUri` ), falling back to a member idea `pageUrl` when file pages are disabled.
- implementation
- mod.rs, html_utils.rs, app.js
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets, html_export.rs:url_base_and_header_link_produce_root_relative_hrefs
html_export_graph_layout
reqlan rq/core_analysis/html_export.rq
The interactive export graph should lay out nodes so labels and circles do not heavily overlap.
Initial placement should settle with the same Obsidian-style force model as layout_physics ( central gravity, edge springs, inverse-square repulsion ).
Rendering uses canvas 2 d ( not SVG DOM ) with shared physics from physics-core.js, inlined into the export asset app.js.
- implementation
- app.js, physics-core.js, graph-physics.ts
html_export_graph_animation
reqlan rq/core_analysis/html_export.rq
Live physics in the HTML export should match Ideas Summary animatePhysics: continuous damped semi-implicit Euler using the defaults from physics-core.js ( same module as graph-physics.ts ), inlined in app.js.
A Live physics toggle pauses and resumes the same simulation state ( default off ); when off, the graph batch-settles then sleeps.
Batch settle must remain responsive per html_export_graph_background_load — yield between chunks rather than freezing the page for large graphs.
Simulation should converge and sleep when calm, waking on filter changes or when Live physics is turned back on, aligned with layout_physics.
Large graphs use a spatial grid + repulsion cutoff in the shared core; all nodes and full labels remain visible.
- implementation
- app.js, physics-core.js, graph-physics.ts
html_export_graph_background_load
reqlan rq/core_analysis/html_export.rq
Interactive HTML export graph boot and layout settle must not monopolise the main thread on large graphs.
Page chrome ( nav, filters, search, other controls ) should stay responsive while the graph initialises.
Graph wiring should start after the first paint / idle opportunity rather than synchronously blocking `DOMContentLoaded`.
When Live physics is off, the initial batch settle should run in yielded chunks ( animation frames or idle callbacks ) so the browser can paint and handle input between steps; keep the boot spinner until the first usable canvas frame, then show progressive settle status.
A new filter / refresh or remount must cancel any in-flight background settle before starting another.
Cross-refs html_export_graph_page, html_export_graph_animation, html_export_graph_interaction.
- status
- done
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_graph_subject
reqlan rq/core_analysis/html_export.rq
When a graph view has a subject or center idea, that node should be visually distinct from peers and externals.
Subject styling should use the brand rust accent against cyan peer nodes.
- implementation
- mod.rs, app.js, styles.css
html_export_graph_labels
reqlan rq/core_analysis/html_export.rq
HTML export canvas graphs implement shared graph_labels ( full names, no ellipsis truncation ).
html_export_graph_label_modes
html_export_graph_label_auto
- implementation
- app.js
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_graph_label_modes
reqlan rq/core_analysis/html_export.rq
Export-surface wiring for graph_label_modes: Labels control on every interactive export graph cycles auto / on / off; Reset restores auto.
- status
- done
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_graph_label_auto
reqlan rq/core_analysis/html_export.rq
Export-surface wiring for graph_label_auto: canvas paint applies continuous zoom opacity ( GRAPH_LABEL_FADE_START → GRAPH_LABEL_FADE_END ); hover / drag stays fully opaque.
Labels stay fully invisible while the graph is initialising or batch-settling so text paint does not lag those phases; zoom fade applies only after settle completes.
Zoom and Fit from html_export_graph_interaction / manual_reframe update opacity each paint.
- implementation
- app.js
- status
- done
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_graph_interaction
reqlan rq/core_analysis/html_export.rq
The interactive export graph should support dragging nodes and panning or zooming the viewport, aligned with view_controls and manual_reframe.
Click-through to idea pages must remain available after drag via click-versus-drag discrimination.
A Fit control should reframe the viewport to the current node set without restarting layout or clearing live physics state.
Zoom and Fit must continuously drive graph_label_auto / html_export_graph_label_auto opacity when Labels is in auto mode.
When file_treatment_toggle is compound: file bounding boxes are hittable — drag moves member nodes together;
clicking the underlined title navigates to the hosting file page ( when `hostFilePageUrl` / `pageUrl` is present ).
When linked: synthetic file ideaset nodes are dragged and clicked like other leaves.
Related: file_treatment_toggle,
webview_export_graph_parity.
html_export_graph_metadata
reqlan rq/core_analysis/html_export.rq
Graph nodes in the HTML export should surface tags, status, and attribute keys on or beside the node, not only as filter inputs.
Attribute values declared on the idea should be reachable from the graph via the idea page and on-node attribute key summary.
- implementation
- app.js, mod.rs, snapshot.rs
html_export_printable_pages
reqlan rq/core_analysis/html_export.rq
Html export should provide static printable pages alongside the interactive site.
Print pages should not depend on the interactive javascript bundle.
Status and tags are nullable: when absent, printable sheets must omit those fields rather than inventing placeholders such as unspecified or empty dashes.
When print pages are browsed in interactive runtime mode, long lists with content below them follow html_export_scrollable_lists.
Idea cards on the printable report follow html_export_print_idea_cards, html_export_print_in_page_anchors, html_export_print_all_attributes, and html_export_print_button.
Stored idea body spaces on print pages follow html_export_print_body_whitespace.
Ordering of cards on the printable report is tracked by html_export_print_order_by.
- implementation
- mod.rs, html_utils.rs, styles.css, html.rs
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_print_idea_cards
reqlan rq/core_analysis/html_export.rq
The printable report page lists ideas as cards in a single column that must remain within the page width on narrow viewports — no horizontal spill from long summaries, file paths, refs, or attribute values.
Cards use a one-column grid ( `minmax(0, 1fr)` ) and wrapping / overflow rules so content reflows instead of overflowing the layout.
Stored idea body spaces on these cards follow html_export_print_body_whitespace.
Cross-refs html_export_printable_pages, html_export_print_in_page_anchors, html_export_print_all_attributes.
- implementation
- mod.rs, styles.css
- status
- done
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_print_body_whitespace
reqlan rq/core_analysis/html_export.rq
The printable report must show the idea body text that the parser stores.
Each per-idea printable sheet must show the stored idea body text.
The parser removes the base indent.
The base indent is the indent of the first body line.
Extra indent on a later line is part of the body text.
A later line with 4 more spaces than the first body line is stored with those 4 spaces.
Print HTML must keep those leading spaces.
Print HTML must not collapse those spaces.
The body text must still wrap inside the card width.
Cross-refs html_export_printable_pages, html_export_print_idea_cards.
- implementation
- mod.rs, styles.css
- status
- done
- tests
- html_export.rs:print_pages_keep_relative_body_indent
html_export_print_in_page_anchors
reqlan rq/core_analysis/html_export.rq
On the printable report page, each idea card has a stable html `id` derived from the idea identity.
Cross-idea links rendered on that page ( title links and inline idea refs in summaries / attributes ) must resolve to same-page `#` fragment urls targeting those ids, not separate idea detail pages.
When browsed with the sticky site topbar, fragment navigation must leave the target card fully visible below the header ( scroll padding / scroll-margin ), not clipped behind it.
Aligns with stable in-page anchors in html_export_internal_links.
Cross-refs html_export_printable_pages, html_export_print_idea_cards.
- implementation
- mod.rs, html_utils.rs, styles.css
- status
- done
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_print_all_attributes
reqlan rq/core_analysis/html_export.rq
Printable report idea cards and per-idea printable sheets must show every declared attribute for the idea, not only status ( or status + tags ).
Attribute values that contain idea refs follow the link rules of the hosting print surface ( html_export_print_in_page_anchors on the report page ).
Cross-refs html_export_printable_pages, html_export_idea_pages.
- implementation
- mod.rs, html_utils.rs
- status
- done
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_print_button
reqlan rq/core_analysis/html_export.rq
Printable report and printable idea sheets include a Print control that opens the browser print dialog ( `window.print` ).
The control must work without the interactive javascript bundle ( inline handler is acceptable ) and should be hidden in the printed output.
Cross-refs html_export_printable_pages.
html_export_print_order_by
reqlan rq/core_analysis/html_export.rq
The printable report should support ordering idea cards by a chosen field or attribute ( for example name, status, file path, or a custom attribute key ).
Consumers should be able to select or configure the sort so printed documents follow a deliberate sequence rather than only the default export order.
Not implemented yet — tracked for a follow-up.
Cross-refs html_export_printable_pages, html_export_print_idea_cards.
- status
- todo
html_export_runtime_modes
reqlan rq/core_analysis/html_export.rq
Html export should support a richer interactive site mode and a leaner document or print-oriented mode from the same export manifest.
Template identifiers should select real rendering behavior rather than metadata only.
Scrollable list viewports from html_export_scrollable_lists apply only in interactive mode; document and print modes keep full-length lists.
html_export_scrollable_lists
reqlan rq/core_analysis/html_export.rq
In interactive runtime mode, long list and table sections that have additional content below them should render inside a scrollable viewport with a max height so lower sections remain reachable without endless page scrolling.
Toolbar titles and filters for those sections should stay outside the scroll viewport.
In document and print runtime modes, those same lists should expand to their full natural height so the export remains readable as a continuous document and suitable for printing.
Browser print of interactive pages should also expand constrained lists to full height.
- implementation
- styles.css, mod.rs
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
html_export_header_link
reqlan rq/core_analysis/html_export.rq
Html export should accept an optional header link ( href + label ) rendered in the topbar ahead of section navigation.
Hosts such as the marketing site build can set this so readers can return to the parent site from any exported page.
When omitted, the topbar shows only the export section nav.
Site embed consumption: spec_html_export.
Often paired with html_export_url_base when the export is mounted under a parent static site.
- implementation
- types.rs, snapshot.rs, mod.rs, styles.css, export.ts, export-spec.mts
- status
- done
- tests
- html_export.rs:url_base_and_header_link_produce_root_relative_hrefs, export.rs:html_export_honours_graph_page_url_base_and_header_link
html_export_url_base
reqlan rq/core_analysis/html_export.rq
Html export should accept an optional urlBase mount prefix ( for example `/spec` or `/reqlan/spec` ).
When set, page and asset hrefs must be root-relative under that prefix so static hosts resolve correctly whether the directory URL includes a trailing slash.
When omitted, exports keep document-relative hrefs suitable for local folder browsing.
Applies across html_export_internal_links and html_export_graph_links; site embed consumption: spec_html_export.
Often paired with html_export_header_link when the export is mounted under a parent static site.
- implementation
- types.rs, html_utils.rs, snapshot.rs, mod.rs, export.ts, export-spec.mts
- status
- done
- tests
- html_export.rs:url_base_and_header_link_produce_root_relative_hrefs, export.rs:html_export_honours_graph_page_url_base_and_header_link
analytical_rust_port
reqlan rq/core_analysis/rust_port.rq
Port analytical_package to Rust: lexer, parser ( index path ), extractor, SQLite index, search, and export.
`@reqlan/analytical` remains the published JS facade ( `createAnalysisRuntime` / `AnalysisApi` / Zustand host state ).
Native work lives in a `crates/` Cargo workspace and ships as per-architecture binaries per rust_binary_distribution.
The editor language server is language_server_rust. This analytical port does not replace that process.
Component plans: rust_crate_layout, lexer_rust, parser_rust, parser_align, indexer_rust, search_rust, export_rust, native_bridge, cutover.
- plan
- goal
Same AnalysisApi behaviour, faster and native, distributed as per-arch npm packages and per-target VSIXes without breaking the shared `<base>/.reqlan` index. The editor LSP is Rust (language_server_rust).
constraints
- Ship per rust_binary_distribution and vsix_export: npm platform packages + host-targeted VSIX; website listing and GitHub-release postinstall out of scope.
- On-disk ideas index schema stays compatible (index) so TS and Rust share application memory during cutover.
- Syntax requirements stay in syntax.rq. The language server parses with `reqlan-parse` (analytical_rust_port). Do not switch the language to tree-sitter (grammar_and_parser).
- Port the context-sensitive lexer, not a naive parser-generator (lexer_bridge_to_syntax, nested_curly_braces, context_sensitive_lexer_scaling).
- Honour nonblocking_index, parse_budget_timeout, rust_mindset, supply_chain.
- Extension host loads the host-matching napi `.node` from the per-target VSIX (extension_host_target); missing core engine is a hard error (no sql.js fallback).
- Interactive HTML graph/search JS and graph physics stay JS assets (html_export_graph_layout).
- Comment-file indexing is index_code_files (native sync, not a Langium comment-grammar pass).
steps
1. Scaffold crates + CI + golden harness (rust_crate_layout).
2. Lexer then parser with recovery and budget (lexer_rust, parser_rust).
3. Extractor + rusqlite index + incremental sync (indexer_rust).
4. Search and analysers (search_rust).
5. Export snapshot and writers (export_rust).
6. napi-rs loader in `@reqlan/analytical`; CLI/MCP first (native_bridge, cutover).
7. Publish platform packages on `analytical/v*` and ship per-target VSIXes (analytical_rust_port, vsix_export).
open
- Language-server process: language_server_rust. CLI `parse` uses the core Rust engine. - status
- in-progress
- tests
- lexer.rs:prose_braces_stay_other, parser.rs:keeps_inline_prose_braces, extract_parity.rs:indexes_scalar_list_block_and_flag_attribute_values, golden_corpus.rs:corpus_idea_names_match_langium_extract, langium-corpus-golden.test.ts:committed dump matches live Langium extract, fuzzy.rs:ranks_exact_and_prefix_matches_ahead_of_subsequence_fuzzy_hits
- todo
- first `@reqlan/analytical-<platform>-<arch>` publish (Trusted Publisher on npmjs.com + analytical/v* tag)
rust_crate_layout
reqlan rq/core_analysis/rust_port.rq
Cargo workspace at repo-root `crates/` ( not inside `packages/analytical` ), crates:
- `reqlan-parse` — lexer, parser, AST, recovery, parse budget
- `reqlan-index` — extract, rusqlite store, mtime sync, diagnostics
- `reqlan-search` — fuzzy / contextual / semantic ranking
- `reqlan-export` — snapshot + html / md / json / csv writers; embed existing HTML JS assets
- `reqlan-analytical` — facade matching `AnalysisApi` + `WorkspaceIndex` operations
- `reqlan-napi` — Node binding for the core engine ( native_bridge )
- `reqlan-lsp` — editor language server ( language_server_rust )
Mature crates only ( rusqlite, napi ): no experimental parser generators for the lexer.
Golden tests compare Rust extract against Langium on the frozen golden_corpus, plus the language-test fixtures ported into `reqlan-parse` / `reqlan-index` tests.
Format: rust_fmt.
Root `pnpm test` runs `test:js` then `test:rust` from package.json. `test:rust` is `cargo test --workspace --exclude reqlan-napi`. GitHub CI compiles crates once, then runs `cargo test` as its own step so crate tests reuse that build ( ci_gate ).
- implementation
- package.json, Cargo.toml
- status
- done
- tests
- golden_corpus.rs:corpus_idea_names_match_langium_extract, langium-corpus-golden.test.ts:committed dump matches live Langium extract, release-ci-gate.test.ts:pnpm test runs crate tests
golden_corpus
reqlan rq/core_analysis/rust_port.rq
Parser / extractor alignment uses a frozen `.rq` tree under `testdata/golden-corpus/`, not live product requirements in `reqlan rq/`.
Production idea lists may change without regenerating the dump. Copy a representative file into the corpus and refresh `crates/reqlan-index/tests/golden/langium-corpus-names.json` only when grammar or extract behaviour needs a new sample.
Langium and Rust both extract name + kind from that tree and must match the committed dump.
Live parse alignment ( elements and refs, both engines in one test ): parser_align.
Comment character ranges on the same tree: comment_span_align.
- status
- done
- tests
- langium-corpus-golden.test.ts:committed dump matches live Langium extract, golden_corpus.rs:corpus_idea_names_match_langium_extract, langium-rust-parse-align.test.ts:golden corpus matches live Langium and Rust snapshots, comment-span-align.test.ts:golden corpus C-style comment ranges match lexer, scanner, and TextMate, parsing.test.ts:parse ontology.rq ideas, parsing.test.ts:parse mid-line triple backticks corpus without swallowing later ideas, golden_corpus.rs:opaque_file_examples_do_not_extract_inline_or_fenced_paths, golden_corpus.rs:mid_line_triple_backticks_keep_later_ideas, golden_corpus.rs:qualified_reference_to_an_import_alias_is_not_a_missing_idea
comment_span_align
reqlan rq/core_analysis/rust_port.rq
On every frozen golden_corpus `.rq` file, `//` and `/* … */` comment character ranges must be identical across:
- the Langium lexer ( hidden `SL_COMMENT` / `ML_COMMENT` )
- `findCommentSpansInText` C-style spans ( host `#` / triple-quote spans are not `.rq` comments )
- TextMate `comment.line.reqlan` and `comment.block.reqlan` scopes
Same-line fences, glob `/**/`, URL `://`, and fenced ` ` ` bodies must not open comments.
Mid-line triple backticks are prose. They must not open a fence or hide later ideas.
Example: `@reqlan/*` in inline code must not open a block comment.
Related: parser_align, code_snippets, comments, fencing_comments, inline_code.
- implementation
- reqlan-token-builder.ts, reqlan-comment-resolver.ts, reqlan-line-fences.ts, patch-textmate.mjs, reqlan.tmLanguage.json, lexer.rs
- status
- done
- tests
- comment-span-align.test.ts:golden corpus C-style comment ranges match lexer, scanner, and TextMate, * is not a block comment, comment-span-align.test.ts:TextMate line-fences run before comments, comment-span-align.test.ts:mid-line triple backticks are not a fence, comment-span-align.test.ts:line-start triple backticks lex as CODE_FENCE and hide inner comments, comment-span-align.test.ts:TextMate code-snippets fences are line-start only, * in block body is not a block comment, * inside complete backtick fences, references.test.ts:findCommentSpansInText does not treat mid-line ``` as a fence, parsing.test.ts:keeps later ideas after mid-line triple backticks, parsing.test.ts:parse rust_port.rq keeps ideas after comment_span_align fence prose, lexer.rs:backticked_slash_star_is_not_a_comment, lexer.rs:mid_line_triple_backticks_are_not_a_code_fence, parser.rs:keeps_ideas_after_mid_line_triple_backticks
lexer_rust
reqlan rq/core_analysis/rust_port.rq
Hand-written Rust lexer that ports reqlan-token-builder.ts:
structural vs prose `{` / `}`, fence opacity, quote-aware comments, `@` only at line start, glob `/**/` not a block comment.
Linear in document size with sparse brace-depth lookup ( context_sensitive_lexer_scaling ).
Owned by `reqlan-parse`; consumed by parser_rust and by language_server_rust.
The Langium token builder remains only for the transitional `node` engine fallback and dual-parser tests.
- status
- done
- tests
- lexer.rs:structural_braces_around_named_block, lexer.rs:prose_braces_stay_other, lexer.rs:glob_star_star_is_not_a_block_comment, lexer.rs:at_only_at_line_start, lexer.rs:url_slashes_are_not_line_comments, lexer.rs:mid_line_triple_backticks_are_not_a_code_fence, lexer.rs:line_start_triple_backticks_are_a_code_fence, lexer.rs:middle_dot_before_brace_does_not_panic
parser_rust
reqlan rq/core_analysis/rust_port.rq
Recursive-descent parser matching reqlan.langium productions into a Rust AST the extractor can walk.
Recovery: nameless `{...}` and local import mistakes still yield a usable document ( recovery_vs_budget ).
Wall-clock parse_budget_timeout via native timeout / cancel — no Node worker process required on the index path.
Open `.rq` buffers and CLI `parse` use `reqlan-parse` ( language_server_rust ).
Langium remains a dual-parser test oracle and the transitional `node` engine fallback — not the default editor LSP.
Alignment contract: parser_align.
- status
- done
- tests
- parser.rs:keeps_inline_prose_braces, parser.rs:recovers_nameless_block, parser.rs:from_import_records_each_token_span, parser.rs:recovers_invalid_from_import_and_keeps_later_ideas, parser.rs:times_out_hang_sentinel, parser.rs:keeps_ideas_after_mid_line_triple_backticks, lexer.rs:mid_line_at_plan_brace_stays_prose, golden_corpus.rs:corpus_idea_names_match_langium_extract, golden_corpus.rs:tutorials_rq_keeps_ideas_after_nested_slides_lists, parsing.test.ts:keeps later ideas after nested @slides lists with mid-line @plan braces, parsing.test.ts:parse tutorials.rq nested @slides lists without parser errors, langium-rust-parse-align.test.ts:golden corpus matches live Langium and Rust snapshots, runtime-engine.test.ts:parse command uses native parseReqlanSource, load-native.test.ts:exposes parseReqlanSource on the engine when present
parser_align
reqlan rq/core_analysis/rust_port.rq
Langium and `reqlan-parse` stay two engines as a dual-parser **test oracle**.
Grammar truth is syntax.rq / reqlan.langium.
The same source must yield the same parse snapshot: top-level elements, live bracket and wiki refs, inline-code count, and fence count.
One Node test runs Langium and native `parseReqlanSource` ( `parseAlignSnapshot` ) together. A committed name dump is not the only check.
The default editor LSP already uses Rust ( language_server_rust ); this idea does not gate that cutover.
Related: golden_corpus, parser_rust, comment_span_align.
- implementation
- align.rs, langium-rust-parse-align.test.ts, lib.rs, parse-source.ts
- status
- done
- tests
- langium-rust-parse-align.test.ts:golden corpus matches live Langium and Rust snapshots, langium-rust-parse-align.test.ts:inline_code_file_example, langium-rust-parse-align.test.ts:inline_code_file_only_line_range, langium-rust-parse-align.test.ts:fenced_file_example, langium-rust-parse-align.test.ts:mid_line_triple_backticks, align.rs:inline_code_file_example_is_not_a_live_ref, align.rs:inline_code_file_only_line_range_is_not_a_live_ref, align.rs:fence_body_is_one_code_snippet_not_inner_refs, align.rs:mid_line_triple_backticks_are_not_a_code_snippet
search_rust
reqlan rq/core_analysis/rust_port.rq
Port fuzzy_search ( separator-insensitive ranking ), contextual_search ( hop-distance rerank ), and semantic_search into `reqlan-search`.
Same `AnalysisApi.searchRequirements` / `--context` contract ( commands ).
Activity-bar idea search uses `WorkspaceIndexRuntime.fuzzy_search` / napi `NativeWorkspaceIndex.fuzzySearch` so ranking stays next to rusqlite and only capped hits cross into JS.
Mixed list includes indexed `.rq` file-name hits ( `kind` `file` ) and pages with `offset` / `limit` ( `truncated` ).
Client-side highlight helpers used by webviews may stay in the TS `./fuzzy-search` export until a shared WASM / JS copy is needed.
- status
- done
- tests
- fuzzy.rs:ranks_exact_and_prefix_matches_ahead_of_subsequence_fuzzy_hits, fuzzy.rs:matches_across_separator_substitutions, fuzzy.rs:fuzzy_search_reads_sqlite_and_returns_ranked_hits, fuzzy.rs:ranks_file_name_hits_with_ideas, fuzzy.rs:pages_ranked_hits_with_offset_and_truncated, fuzzy_search.rs:workspace_index_fuzzy_search_ranks_without_exporting_catalog, fuzzy_search.rs:workspace_index_fuzzy_search_includes_file_name_hits, contextual.rs:nearer_ideas_rank_above_farther_with_equal_text_scores, contextual.rs:reranks_using_graph_edges_from_context_seeds, semantic.rs:ranks_name_hits_ahead_of_summary_and_tag_hits, semantic.rs:scores_reference_labels_and_query_tokens
export_rust
reqlan rq/core_analysis/rust_port.rq
Port export_pipeline: `buildExportSnapshot` then HTML / markdown / JSON / CSV writers in `reqlan-export`.
Interactive HTML JS ( graph canvas, list filters, search bars ) stays static assets bundled into the export — not rewritten in Rust ( html_export, html_export_graph_animation ).
Hosts still call `NativeAnalysisApi.exportHtml` / `exportMarkdown` / `exportJson` / `exportCsv`; they do not grow format writers.
PDF remains print-HTML ( pdf_export ); html_export_print_order_by stays a product follow-up, not a port blocker.
- status
- done
- tests
- json_export.rs:json_export_lists_persisted_ideas, html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets, html_export.rs:overview_status_and_tag_rollups_link_with_filters, html_export.rs:url_base_and_header_link_produce_root_relative_hrefs
native_bridge
reqlan rq/core_analysis/rust_port.rq
The Rust engine is the analytical core ( parse, index, search, export, typed queries, git-dates, overview coverage, barrel plan ) — not an optional addon.
`@reqlan/analytical` is a typed napi facade ( specta `generated.ts` ) plus thin Node helpers ( `createBase`, path utils, `SqliteIndexStore` wrappers over typed napi ).
It does not depend on Langium, `@reqlan/language`, or Zustand.
Webview-only helpers ( search highlight, filter labels, file-treatment, context signals / model, graph physics ) live in the extension package.
Interactive HTML JS stays in `crates/reqlan-export/assets`.
Native owns: parse-for-index, persist, query, search, export execution, IndexService / WorkspaceIndex sync,
and the index lifecycle FSM + status snapshot via `NativeWorkspaceIndex` + `NativeSqlDb`. The FSM
( `opening` / `syncing` / `ready` / `error` ), counts, in-memory sync progress / cancel, last error, file-index
issues ( cap 500 ), and the document-update / workspace-change rings ( cap 50 ) live in `WorkspaceIndexRuntime`;
TS reads them through `statusSnapshot()`. Durable diagnostics persist in `index-diagnostics.sqlite`.
Consumers: cli_package and MCP import `@reqlan/analytical/core` so they never load Langium;
the extension host uses the per-target VSIX ( vsix_export, extension_host_target ).
The host-matching `.node` is required at runtime; there is no sql. js fallback.
- status
- in-progress
- tests
- load-native.test.ts, native-packaging.test.ts, native-headless-entry.test.ts, open-analysis-api.test.ts, native-export-request.test.ts, workspace-paths.test.ts, index-windows-paths.test.ts, export.rs:html_export_honours_graph_page_url_base_and_header_link
- todo
- publish first `@reqlan/analytical-<platform>-<arch>` release (Trusted Publisher on npmjs.com + analytical/v* tag)
cutover
reqlan rq/core_analysis/rust_port.rq
Native engine is required for CLI, MCP, and the extension IndexService path ( no `REQLAN_ANALYTICAL_ENGINE=js` escape hatch ).
Order: golden parse / extract → headless CLI `analyse` / `search` / `export` → MCP → extension via platform VSIX ( host-matching napi `.node` required ).
Shared base `.reqlan` DB is schema v4 rusqlite; fixtures verify reopen compatibility.
The default editor LSP is language_server_rust. Langium remains only as the transitional `node` engine fallback and dual-parser oracle ( parser_align ).
- status
- done
- tests
- schema.rs:opens_at_schema_version_4, schema.rs:schema_v4_columns_round_trip_git_count_and_mtime, schema.rs:schema_v4_file_reopens_after_drop, schema.rs:opens_sqljs_written_schema_v4_fixture, schema-v4-roundtrip.test.ts, open-analysis-api.test.ts, runtime-engine.test.ts, native-headless-entry.test.ts
port_phases
reqlan rq/core_analysis/rust_port.rq
Ideaset (port_phases)
ts_interface
reqlan rq/core_analysis/rust_port.rq
The TS interface over the Rust functionality stays fully typed via specta ( `crates/reqlan-analytical` `export-ts` → `packages/analytical/src/native/generated.ts` ).
Specta copies Rust doc comments. `export-ts` rewrites those `rq:` paths from crate-src depth to `packages/analytical/src/native` depth.
- implementation
- export_ts.rs, lib.rs
- status
- done
- tests
- generated.ts, generated-native-types.test.ts, export_ts.rs:committed_generated_ts_matches_specta_export, export_ts.rs:rewrite_generated_ts_comment_paths_adds_one_hop
search
reqlan rq/core_analysis/search.rq
Search over the requirement graph — find ideas by name, body, tags, and related signals.
Surfaces: fuzzy_search, file_search, contextual_search, semantic_search, katz_search.
Consumed by CLI `reqlan search`, MCP / chat tools, Ideas Summary, and the activity-bar search pane.
Rust ranking engine: search_rust.
- todo
- flesh out shared search UX / ranking contract across surfaces
fuzzy_search
reqlan rq/core_analysis/search.rq
Quick ranked idea search by name, summary, and tags.
Separator and word-order behaviour: fuzzy_search_whitespace.
Also supports prefix, substring, and character-subsequence ( fuzzy ) ranking.
Skips ideaset container rows; empty query returns all non-ideaset ideas ( callers may require a non-empty query ).
Ranking engine: search_rust `reqlan-search` ( `fuzzy_search` / `search_ideas` ).
Also returns file_search hits mixed into the same ranked list ( kind `file` ).
Pagination: fuzzy_search_pages.
Activity-bar search calls native-workspace-index.ts `NativeWorkspaceIndex.fuzzySearch` so the host never copies the idea catalog into JS.
Client-side highlight helpers stay in fuzzy-search.ts.
- status
- done
- tests
- workspace-index.test.ts:fuzzySearch ranks from the native index without listing all ideas in JS, workspace-index.test.ts:fuzzySearch returns file-name hits and pages with offset, fuzzy.rs:ranks_exact_and_prefix_matches_ahead_of_subsequence_fuzzy_hits, fuzzy.rs:fuzzy_search_reads_sqlite_and_returns_ranked_hits, fuzzy.rs:ranks_file_name_hits_with_ideas, fuzzy.rs:pages_ranked_hits_with_offset_and_truncated, fuzzy_search.rs:workspace_index_fuzzy_search_ranks_without_exporting_catalog
fuzzy_search_whitespace
reqlan rq/core_analysis/search.rq
Matching treats `_`, `-`, `.` / `...` / `…`, and whitespace as interchangeable separators
so queries like `cli package`, `cli_package`, and `cli-package` hit the same idea.
Prefers query word order, but still matches when words are reordered or when intermediate name words are missing
( e. g. `package cli` → `cli_package`, `search actions` → `search_code_actions` ).
Extends fuzzy_search; implementation fuzzy-search.ts.
- status
- done
- tests
- fuzzy.rs:collapses_underscore_hyphen_dots_ellipsis_and_whitespace, fuzzy.rs:matches_across_separator_substitutions, fuzzy.rs:matches_reordered_and_partial_word_queries
fuzzy_search_pages
reqlan rq/core_analysis/search.rq
fuzzy_search accepts `offset` + `limit` over the already-ranked mixed idea + file list.
`truncated` is true when more hits exist after the returned page ( callers show `{n}+` rather than a full count ).
Used by search_pane_load_more.
- implementation
- fuzzy.rs, native-workspace-index.ts, fuzzy-search.ts
- status
- done
- tests
- fuzzy.rs:pages_ranked_hits_with_offset_and_truncated, workspace-index.test.ts:fuzzySearch returns file-name hits and pages with offset
file_search
reqlan rq/core_analysis/search.rq
Rank indexed `.rq` files and comment-bearing code files by basename, stem, and path using the same
separator-insensitive matching as fuzzy_search / fuzzy_search_whitespace.
Hits use kind `file`; id is the indexed file URI; name is the basename; line start is 0.
Empty query does not dump the file catalog.
Mixed into file_search so one list ranks ideas and files together.
Code files are those persisted by index_code_files.
Surfaces: native `fuzzy_search` via native-workspace-index.ts, search_pane_file_hits.
click_input uses this mix when click has no exact match.
- implementation
- fuzzy.rs, store.rs, sqlite-store.ts, native-workspace-index.ts, fuzzy-search.ts
- status
- done
- tests
- fuzzy.rs:ranks_file_name_hits_with_ideas, workspace-index.test.ts:fuzzySearch returns file-name hits and pages with offset, fuzzy_search.rs:workspace_index_fuzzy_search_includes_file_name_hits, fuzzy_search.rs:workspace_index_fuzzy_search_includes_comment_code_files
contextual_search
reqlan rq/core_analysis/search.rq
Search string plus an optional context list of relative `.rq` paths, `path#idea` refs, or bare idea names.
Runs semantic_search, then re-ranks with min undirected hop distance from any resolved context idea
and exponential decay ( idea_graph_distance ): `finalScore = textScore * 2^(-minHop)` ( unreachable floor = 8 hops ).
Surfaces: native-analysis-api.ts `searchRequirements(..., { context })` and CLI `reqlan search --context` ( search.ts ).
Implements search_with_context. PageRank ( pagerank ) and full context_scope_v2 ingestion remain future work.
Default ranking does not use Katz. Opt in with katz_search.
Complements fuzzy_search when neighbourhood / context should bias ranking.
click_input ranks ambiguous click matches the same way, with session ideas as context.
- status
- done
- tests
- contextual.rs:nearer_ideas_rank_above_farther_with_equal_text_scores, contextual.rs:reranks_using_graph_edges_from_context_seeds
katz_search
reqlan rq/core_analysis/search.rq
Search can bias matches by inbound Katz centrality ( katz_centrality ).
The bias is off unless the caller sets it.
CLI flag: `reqlan search <query> --katz`.
API field: `SearchRequirementsOptions.katz`.
When the bias is on, the score is `textScore * (1 + katzScore)`.
The match reasons include `katz:<score>`.
Context hop decay runs first. The Katz multiplier runs second.
When the bias is off, match order and scores stay on the text ranking.
- implementation
- katz.rs, api.rs, native-analysis-api.ts, search.ts
- status
- done
- tests
- katz.rs:katz_bias_is_off_by_default_and_lifts_the_higher_score_when_on, katz.rs:katz_bias_reports_a_missing_score
semantic_search
reqlan rq/core_analysis/search.rq
Broader token / edge-label search over candidates through native-analysis-api.ts.
Prefer fuzzy_search for fast name-oriented lookup with separator-insensitive matching.
- todo
- true
scope
reqlan rq/development/build.rq
extension build steps for local development and CI
extension_build
reqlan rq/development/build.rq
Production builds for the VS Code extension are orchestrated by build.mjs.
Run from the extension package: `pnpm run build` or `node scripts/build.mjs`.
Workspace-wide builds also run langium generation and sibling packages via the root `pnpm run build`.
Local and F5 builds use incremental_extension_build; VSIX prepublish uses the forced path.
incremental_extension_build
reqlan rq/development/build.rq
Extension builds fingerprint inputs and outputs per independently cacheable artifact:
- Langium generated sources / TextMate grammar
- logo media
- generated marketplace README
- each of the five Vite webviews separately
- extension-host / language-server esbuild outputs
Host napi staging ( extension_host_native_stage ) always runs: cargo is incremental locally; Azure stages matrix artifacts and skips a second cargo compile in the package job.
A step is skipped only when its command / input fingerprint and current output-content fingerprint both match the cache under `packages/extension/out/`.
Missing, changed, or manually edited output invalidates that step.
Fingerprint walks skip `node_modules` so Vite scratch files under `.vite-temp` and installed deps do not race or inflate hashes; dependency identity stays in `pnpm-lock.yaml` via shared inputs.
Webview output fingerprints cover each complete emitted directory, including future lazy chunks. Host-bundle inputs include bundled phonebook data as well as workspace package output.
TypeScript retains its native `tsc -b` project-reference incrementality.
TextMate syntax copies are cached by content; Cursor-skill sync still runs because it targets workspace-external state.
`pnpm run build:force` / `node scripts/build.mjs --force` bypasses all cache entries.
`vscode:prepublish` uses forced mode with `--skip-native` so `vsce package --target` cannot replace a staged per-target `native/` with the packaging agent's host binary ( vsix_export ).
`clean` removes `out/`, including the cache, so clean builds remain cold.
Root `pnpm run build:ext` delegates only to the extension package. The extension build generates Langium artifacts when their fingerprints change, then its `tsc -b` builds language / analytical project references before downstream fingerprints are evaluated. It does not rebuild unrelated CLI, MCP, site, or test projects.
- status
- done
- tests
- incremental-build.test.ts, incremental-build.test.ts:ignores node_modules when fingerprinting a directory tree, native-packaging.test.ts
extension_host_native_stage
reqlan rq/development/build.rq
Local F5 and `pnpm run build` / `build:ext` stage the host-matching core engine `.node` into `packages/extension/native/` so activation loads the same layout as a per-target VSIX ( vsix_export, native_host_binary_development ).
The same build copies the `.node` into `packages/analytical-native/<napiSuffix>/` so the workspace optionalDependency matches a production npm install ( rust_binary_distribution ).
The orchestrator builds `cargo build -p reqlan-napi -p reqlan-lsp --release` when needed, then copies `reqlan_napi.node` beside the extension. It is not a separate manual install.
That command writes `reqlan-lsp` into `crates/target` ( language_server_rust ).
Azure compiles the native_targets matrix, then stages those binaries with `prepare-native-packages.mjs --binary-dir` before tests and VSIX packaging. Versions come from git at the `ext/v*` tag. Do not fetch platform packages from npm on Azure ( extension_distribution ).
Implementation: stage-host-native.mjs, ensure-host-native.mjs, build.mjs, azure-pipelines.yml.
- status
- done
extension_media_build
reqlan rq/development/build.rq
Extension logo assets are generated by generate-media.mjs from logo.svg.
PNG ( `media/logo.png` ) is tracked in git and used as the packaged icon for marketplace, language file icon, and activity bar ( Azure Marketplace rejects SVG ).
WebP and SVG copies remain build outputs ( gitignored ); regenerate via `build:media` when the source logo changes.
Invoked as `pnpm run build:media` at the start of build.mjs.
extension_readme_build
reqlan rq/development/build.rq
Generate `packages/extension/README.md` from generate-readme.ts and README. template. md before VSIX packaging.
Marketplace links are resolved from phonebook.ts; changelog body comes from packages / extension / CHANGELOG. md ( Changesets output ).
Invoked as `pnpm run build:readme` at the start of build.mjs.
Requirement: extension_readme.
build_prepare
reqlan rq/development/build.rq
Copy TextMate grammars from the language package into extension syntaxes.
Sync Cursor agent skills from extension sources into `.cursor/skills`.
The orchestrator caches `build:syntaxes` independently and always runs the external Cursor-skill sync before webview and host bundling.
webview_build
reqlan rq/development/build.rq
Svelte webview UI is bundled with Vite per core.rq.
Configs: vite.config.ts, vite.config.ts, vite.config.ts
Output lands in `packages/extension/media/webviews/` for the extension host to load.
The onboarding webview inlines thanks-for-installing.template.rq via Vite `?raw` for the in-page language example; the template source stays excluded from the VSIX.
Requirement: installation_event.
Watch mode during development: `bash scripts/watch.sh` vite `--watch` alongside tsc and esbuild.
- steps
- npx vite build --config webviews/ideas-summary/vite.config.ts, npx vite build --config webviews/activity-bar/vite.config.ts, npx vite build --config webviews/onboarding/vite.config.ts
typescript_emit
reqlan rq/development/build.rq
Package TypeScript emit goes to each package `out/` via `tsc -b` project references ( tsconfig.build.json ).
Shared compiler options live in tsconfig.base.json. tsconfig.json is a solution file ( `files: ` ) so a plain `tsc` / VS Code " tsc: build " does not write `.js`, `.d.ts`, or `.js.map` next to sources.
Webview tsconfigs are `noEmit` — Vite bundles to `packages/extension/media/webviews/`.
A clean compile must generate Langium sources first ( typescript_compile ).
- status
- done
typescript_compile
reqlan rq/development/build.rq
Langium writes `packages/language/src/generated` ( ast, grammar, module ). That directory is gitignored.
`tsc -b tsconfig.build.json` fails on a clean checkout if those files are missing.
Root script `build:tsc` is `langium:generate` then that `tsc -b`. Full `pnpm run build` starts with `build:tsc`.
GitHub CI, Azure package build, and npm deploy use `build:tsc` so compile matches a clean local build ( prerelease_tests, ci_gate, npm_distribution ).
GitHub CI compiles the TypeScript workspace once in the sequential job, then reuses that emit for check and package tests ( check_meta_implementation ).
`langium generate` validates langium-config.json against the langium-cli schema.
langium-cli 4. 3. 0 does not set schema `$id`. jsonschema 1. 5. 0 then throws `ERR_INVALID_URL` for `#/$defs/languageItem` on Node 24.
The workspace pins jsonschema 1. 4. 1 for langium-cli in pnpm-workspace.yaml until a langium-cli release includes that `$id`.
- implementation
- package.json, pnpm-workspace.yaml, langium-config.json, ci.yml, deploy-npm.yml, azure-pipelines.yml, .gitignore
- status
- done
- tests
- release-ci-gate.test.ts, release-ci-gate.test.ts:TypeScript compile generates Langium sources first, langium-generate-config.test.ts, langium-generate-config.test.ts:langium-cli schema validates langium-config.json
extension_typecheck
reqlan rq/development/build.rq
Extension TypeScript sources are checked with `tsc -b tsconfig.json` before bundling.
`noEmit: true` — compilation output comes from esbuild, not tsc.
extension_bundle
reqlan rq/development/build.rq
The extension host ( `src/extension/main.ts` ) and language server ( `src/language/main.ts` ) are bundled with esbuild per esbuild.mjs.
The host-matching core engine `.node` is staged under `native/` by extension_host_native_stage for F5 and for per-target VSIX packaging; it is not inlined into `main.cjs`.
Output: CommonJS `.cjs` files under `packages/extension/out/`.
`vscode` remains external; a small `Object.groupBy` polyfill is injected for older Node runtimes.
- steps
- node esbuild.mjs
rust_fmt
reqlan rq/development/commit.rq
CI runs `cargo fmt --all` in write mode on all crates ( rust_crate_layout, rustfmt.toml ).
Format is a chore, not a gate: an unformatted tree does not fail the job.
On same-repo pull requests, if fmt changes files, CI commits `chore: cargo fmt` and pushes to the PR branch.
Fork PRs and `workflow_call` ( release ) only format the working tree; they do not push.
Recursion stops because: ( 1 ) pushes with the default `GITHUB_TOKEN` do not start new workflow runs; ( 2 ) a second run finds no diff after fmt, so it does not commit again.
Pull requests and the release workflow share the same sequential CI job ( ci_gate ).
Git pre-commit runs the same formatter in write mode so local commits stay formatted.
Skip when no crate Rust is staged, format in place and restage, skip merge / rebase, `SKIP_RUST_FMT=1` escape hatch.
package.json `prepare` sets `core.hooksPath` to `.githooks`.
- implementation
- ci.yml, release.yml, pre-commit, pre-commit-rust-fmt.mjs, install-git-hooks.mjs, package.json, rustfmt.toml
- status
- done
- tests
- rust-fmt-hook.test.ts, rust-fmt-hook.test.ts:selects only staged crate rust sources, rust-fmt-hook.test.ts:runs cargo fmt --all in crates then restages the rust files, rust-fmt-hook.test.ts:CI formats crates and auto-commits on same-repo PRs, release-ci-gate.test.ts:release calls sequential CI before versioning
scope
reqlan rq/development/core.rq
these requirements describe the actual development of the reqlan language and tooling itself
modulurisation
reqlan rq/development/core.rq
files should be small
succinct
reqlan rq/development/core.rq
maximised meaning to character ratio.
hierarchy_of_requirements
reqlan rq/development/core.rq
user request trumps the reqlan rq requirements, and reqlan rq trump the current implementation.
stack
reqlan rq/development/core.rq
- Requirements are documented with reqlan in the reqlan rq folder.
- Language grammar truth is syntax.rq; the default editor LSP is Rust ( `reqlan-lsp` ).
- Langium in `@reqlan/language` remains a dual-parser oracle and the transitional `node` engine fallback.
- VS Code extension host is in extension; open-buffer features run in `crates/reqlan-lsp`.
- vscode webviews are implemented with svelte
- Extension build pipeline is documented in build.rq
pnpm
reqlan rq/development/core.rq
Must use pnpm for all js package management across the monorepo ( packages, extension, site ).
pnpm_val
reqlan rq/development/core.rq
Root `pnpm run val` chains `check`, then `test`, then `build` ( package.json ).
Use for local / ingestion validation ( _file ).
- status
- done
iconify_stack
reqlan rq/development/core.rq
Icons use Iconify offline — bundled at build time, not fetched from a CDN at runtime.
Icon data comes from npm packages listed under the `icons` key in phonebook.json per phonebook_icons.
phonebook_icon_keys
reqlan rq/development/core.rq
per phonebook_icons
A phonebook link or package can omit `icon`. If `icon` is present, it is an object with `set` and `name`.
Set ids and lookup URLs are canonical in phonebook.json. icons.
Use each set's `search` URL to find replacement slugs when a name changes or an icon is removed upstream.
Typed helpers live in phonebook.ts: `formatPhonebookIconKey`, `getPhonebookIconSearchUrl`.
- status
- done
current_link_icons
reqlan rq/development/core.rq
Slugs are defined on each link in phonebook.json:
- `site` → mdi / web
- `vsc` → simple-icons / visualstudiocode
- `openvsx` → simple-icons / vscodium ( proxy; no Open VSX slug in Simple Icons )
- `github` → simple-icons / github
- `discord` → simple-icons / discord
- `github-sponsors` → simple-icons / githubsponsors
- `email` → mdi / email-outline
- `sticker-form` → mdi / sticker-emoji
Package entries under `packages` all use simple-icons / npm:
- `language`, `analytical`, `cli`
rust_mindset
reqlan rq/development/core.rq
- code should be complete
- nulls should be safe and deliberate
- fallbacks should be used sparingly
- incomplete code should be marked as such
- comments should describe final desired state of the code, not the current state; they should be timeless.
- tests should be local
code_comment_references
reqlan rq/development/core.rq
code comments should include reference to their respective rq references.
testing
reqlan rq/development/core.rq
tests should have comment references to the requirements they serve to test. per functional-code-comment-references.rq
- tests
- testing.test.ts:each test file includes rq comment references to its requirements
stopgap
reqlan rq/distribution/distribution.rq
Stopgap distribution is at https://marketplace.visualstudio.com/manage/publishers/reqlan
version_management
reqlan rq/distribution/distribution.rq
Package versions are managed with Changesets via config.json.
Publishable channels ( each tag-driven ):
- Marketplace / Open VSX: extension_package ( private npm package; tagged `ext/v*` )
- GitHub Pages: site_package ( tagged `site/v*` )
- npm: `@reqlan/language`, `@reqlan/analytical`, `@reqlan/cli`, and `@reqlan/mcp` ( tagged `language/v*`, `analytical/v*`, `cli/v*`, `mcp/v*` )
`reqlan-extension` has its own semver. It is not version-locked to `@reqlan/analytical`. The extension can update independently of the analytical surfaces it uses ( version_management ).
The version of `@reqlan/analytical` is the single source of truth for every `@reqlan/analytical-<platform>-<arch>` package ( rust_binary_distribution ). Platform packages are in the Changesets `ignore` list ( `@reqlan/analytical-*` ). Git `@reqlan/analytical` does not list them as `optionalDependencies`, so `changeset version` can run. This workspace still links the checkout packages during `pnpm install` via `packageExtensions` in pnpm-workspace.yaml ( `workspace:*`, not npm ). After `changeset version`, prepare-native-packages.mjs copies the analytical version onto each platform package. The published tarball lists pinned `optionalDependencies` ( `--publish-versions` ) so CLI and MCP customers get the host binary.
Platform native packages are not a separate tag channel; they ride `analytical/v*` ( version_management ).
VSIX packaging uses the package. json versions in that git commit ( vsix_native_not_from_npm ).
`@reqlan/language`, `@reqlan/cli`, `@reqlan/mcp`, and the site keep their own versions.
Contributors record release intent by adding a changeset file when a publishable package changes.
- status
- done
- tests
- native-packaging.test.ts, native-packaging.test.ts:analytical version is SSOT for platform packages; Changesets ignores them, analytical optionalDependencies are publish-only, not in git
npm_distribution
reqlan rq/distribution/distribution.rq
npm publishing runs only when a `language/v*`, `analytical/v*`, `cli/v*`, or `mcp/v*` tag is pushed.
Tags are created by deployment_flow; the npm workflow does not publish on ordinary commits.
The workflow builds platform binaries when `@reqlan/analytical` was bumped ( `analytical/v*` tag, or `analytical_tag` from the release workflow ). It does not use `github.event_name == 'workflow_call'` for that gate: in a reusable workflow that name is the caller event ( `push` ), and `npm_ref` is the first language / analytical / cli / mcp tag, so a language bump would skip natives.
It then publishes each package in sequence with `pnpm --filter <pkg> publish --access public --no-git-checks`.
The sequence is language, then all platform packages for native_targets, then `@reqlan/analytical`, then cli, then mcp.
The workflow does not publish `@reqlan/analytical` until every platform package of that `@reqlan/analytical` version is on the npm registry or was published in the same job ( rust_binary_distribution ).
require-natives-published.mjs enforces that gate from the analytical package. json version ( not Changesets ).
Before each package publishes, skip-already-published.mjs with `--filter <pkg>` checks the public npm registry and skips that step when the version is already published ( sets `should_publish=false` ). That avoids re-attempting already-published versions under OIDC.
Auth uses npm trusted publishing ( OIDC ) from GitHub Actions — no long-lived `NPM_TOKEN`.
Workflow requirements: `permissions.id-token: write`, Node ≥ 22. 14 with npm ≥ 11. 5. 1, registry `https://registry.npmjs.org`.
Each of `@reqlan/language`, `@reqlan/analytical`, `@reqlan/cli`, `@reqlan/mcp`, and every `@reqlan/analytical-<platform>-<arch>` platform package must have a Trusted Publisher on npmjs. com for GitHub Actions with org / user `littletuna4`, repository `reqlan`, workflow filename `deploy-npm.yml`, allowed action `npm publish`.
Package `repository.url` must match `https://github.com/littletuna4/reqlan.git`. Provenance attestations are generated automatically for public packages from this public repo.
Bootstrap: first publish of each scoped package can be done locally ( you must be logged in to npm as an `@reqlan` org member ) with `pnpm --filter @reqlan/language publish --access public --no-git-checks`, then platform packages, then analytical, then cli, then mcp — or wait for the trusted-publisher CI path after packages exist and Trusted Publisher is configured.
Note: Packages must be `private: true` to skip local `changeset publish` ( `pnpm run release:npm` ), as with `reqlan-extension`. Platform packages are in the Changesets `ignore` list ( `@reqlan/analytical-*` ). Git `@reqlan/analytical` does not list them as `optionalDependencies`. prepare-native-packages.mjs `--publish-versions` writes pinned optionalDependencies for the npm checkout only. CI publishes platform packages per-package after binaries are built and does not use `changeset publish` for those tarballs.
Published packages declare `publishConfig.access: public`.
Trusted Publisher is configured on npmjs. com for each `@reqlan/analytical-<platform>-<arch>` package
- implementation
- deploy-npm.yml, skip-already-published.mjs, require-natives-published.mjs, prepare-native-packages.mjs, collect-napi-binary.mjs, package.json
- status
- in-progress
- tests
- native-packaging.test.ts, analytical, native-packaging.test.ts:deploy-npm builds natives when analytical was bumped, not when npm_ref is language, native-packaging.test.ts:analytical version is SSOT for platform packages; Changesets ignores them, analytical optionalDependencies are publish-only, not in git, require-natives-published.test.ts
native_targets
reqlan rq/distribution/distribution.rq
Canonical VS Code `targetPlatform` / npm `os` + `cpu` tuples for native distribution:
- `win32-x64`
- `win32-arm64`
- `linux-x64`
- `linux-arm64`
- `darwin-x64`
- `darwin-arm64`
napi-rs package suffixes map as: `linux-*-gnu`, `darwin-*`, `win32-*-msvc` ( gnu-only for linux; musl / alpine out of scope for the first matrix ).
Azure `build_native` uses the same tuples and `ciImage` from native-targets.mjs.
Used by rust_binary_distribution, vsix_export, extension_host_target, and native_host_binary.
Implementation: native-targets.mjs.
- status
- done
rust_binary_distribution
reqlan rq/distribution/distribution.rq
One platform-specific npm package per native_targets tuple: `@reqlan/analytical-<platform>-<arch>` ( napi suffixes: `linux-x64-gnu`, `linux-arm64-gnu`, `darwin-x64`, `darwin-arm64`, `win32-x64-msvc`, `win32-arm64-msvc` ).
Each package declares `os` and `cpu`, contains the matching core engine `.node`, and uses the `@reqlan/analytical` package. json version as the single source of truth. prepare-native-packages.mjs writes that version. Changesets ignores `@reqlan/analytical-*` in config.json. Git `@reqlan/analytical` does not list platform packages as `optionalDependencies`; this workspace links them through `packageExtensions` in pnpm-workspace.yaml. The published tarball lists pinned optionalDependencies ( `--publish-versions` ) ( version_management ).
CLI and MCP install the host-matching binary from those published optionalDependencies.
The published tarball runs published_host_native_install so a host miss prints a warning.
Published on the existing `analytical/v*` channel ( npm_distribution / release_tagging ); not a separate tag channel.
The napi build runs when this channel moved: a direct `analytical/v*` tag, or `analytical_tag` from deployment_flow. The first npm tag ( `npm_ref` ) can be `language/v*` in the same release, so that ref is not the native-build gate.
Website download listing and GitHub-release postinstall are later follow-ups ( out of scope here ).
Engine port: analytical_rust_port / native_bridge.
Per-target VSIX packaging uses the same package layout under analytical-native, filled by Azure from this git commit ( vsix_export, vsix_native_not_from_npm ). npm tarballs of those packages are for CLI / MCP only.
`collect-napi-binary.mjs` copies `reqlan-lsp` only with `--with-lsp`. The npm workflow does not pass that flag. Azure does, because the VSIX ships `bin/reqlan-lsp` ( rust_binary_distribution ).
Implementation: analytical-native, prepare-native-packages.mjs, require-natives-published.mjs, check-host-native.mjs, config.json, deploy-npm.yml build-native job, azure-pipelines.yml build_native job.
- plan
- goal
Ship per-architecture core engine binaries beside `@reqlan/analytical` so CLI, MCP, and per-target VSIXes can load the Rust engine for the extension-host platform.
constraints
- optionalDependencies (not devDependencies) for runtime consumers.
- VSIX binaries come from Azure `build_native` on the `ext/v*` git tag, not from npm.
- Trusted publishing and `analytical/v*` tagging stay npm_distribution / release_tagging for CLI/MCP.
- gnu-only linux; musl and GitHub-release postinstall out of scope.
- Website binary listing deferred.
- Do not publish `@reqlan/analytical` until every platform package of that version is deployed (rust_binary_distribution).
steps
1. Scaffold six platform packages with os/cpu and the napi binary. (done)
2. Wire optionalDependencies on published `@reqlan/analytical` only; git omits them so Changesets can ignore platform packages. (done)
3. Cross-compile `reqlan-napi` for native_targets on the npm channel. The platform package contains only the `.node`. That job does not build `reqlan-lsp`. (done in deploy-npm.yml)
4. Publish platform packages on `analytical/v*` before `@reqlan/analytical`.
5. Prefer optionalDependency resolution in the loader; keep crates/target fallback for local dev by walking to repo-root `crates/Cargo.toml` (not `packages/crates` from `out/native`). (done) - status
- in-progress
- tests
- load-native.test.ts, native-packaging.test.ts, analytical, native-packaging.test.ts:deploy-npm builds natives when analytical was bumped, not when npm_ref is language, native-packaging.test.ts:analytical version is SSOT for platform packages; Changesets ignores them, analytical optionalDependencies are publish-only, not in git, require-natives-published.test.ts
- todo
- Trusted Publisher registration for platform packages on npmjs.com
extension_host_target
reqlan rq/distribution/distribution.rq
The extension host must load the native core engine for its machine.
The selection strategy is native_host_binary.
IndexService and WorkspaceIndex use `NativeWorkspaceIndex` ( native_bridge ).
If the engine is missing, activation fails.
Loader: load-native.ts.
The extension registers search folders from index.ts.
- status
- in-progress
- todo
- first `@reqlan/analytical-<platform>-<arch>` release not yet published
extension_package
reqlan rq/distribution/distribution.rq
The VS Code extension lives in packages / extension with npm package name `reqlan-extension` ( Marketplace / Open VSX id `reqlan.reqlan-extension` ).
Its package. json version is the Marketplace and Open VSX release version. That version is independent of `@reqlan/analytical` ( version_management ).
- status
- done
- tests
- native-packaging.test.ts:analytical version is SSOT for platform packages; Changesets ignores them
site_package
reqlan rq/distribution/distribution.rq
The static site lives in site / with npm package name `site`.
Its package. json version identifies site releases for tagging.
deployment_flow
reqlan rq/distribution/distribution.rq
On push to main, the release workflow first completes ci_gate.
If pending changesets remain, it then applies them with `pnpm changeset version`.
This bumps package. json for each affected package and writes changelogs.
prepare-native-packages.mjs then copies the `@reqlan/analytical` version onto each platform package ( version_management ).
The workflow commits the result, creates annotated tags for every bumped publishable package, and pushes the commit and tags back to main.
Release tags use `site/v{version}`, `ext/v{version}`, `language/v{version}`, `analytical/v{version}`, `cli/v{version}`, and `mcp/v{version}` where `{version}` is the semver from that package's package. json.
Deployment is tag-driven for every channel per release_tagging; after ci_gate, the release workflow only versions and tags.
GitHub Actions pushes with the default `GITHUB_TOKEN` do not trigger other workflows, so site and npm deploy are also invoked directly from the release workflow.
Optional `RELEASE_PAT` allows tag pushes to trigger downstream workflows for manual reruns and external CI.
Recursive runs are prevented by skipping the release workflow for release commits.
Tag patterns and downstream deploy workflows follow release_tagging.
The implementation lives in release.yml.
ci_gate
reqlan rq/distribution/distribution.rq
Pull-request CI and the main release pipeline share one sequential workflow: ci.yml.
deployment_flow must not apply changesets or create tags until that workflow succeeds.
Order in one job: install workspace packages, compile crates and TypeScript once, then crate tests, check, then JS / TS tests ( prerelease_tests, check_meta_implementation, rust_fmt ).
`@reqlan/*` packages come from this git checkout ( `workspace:*` ), not from the npm registry. Platform native packages are linked the same way in this workspace through `packageExtensions` in pnpm-workspace.yaml; they are not listed in git `@reqlan/analytical` `optionalDependencies`.
A push to main does not start CI a second time as an independent workflow; release.yml calls ci.yml with `workflow_call`.
Because ci.yml declares `permissions.contents: write`, the caller job in release.yml must grant `contents: write` when invoking it.
The version-bump commit ( `chore(release):` ) skips the gate and the version job to prevent a recursive run.
- implementation
- release.yml, ci.yml, assert-workspace-reqlan.mjs
- status
- done
- tests
- release-ci-gate.test.ts, release-ci-gate.test.ts:release calls sequential CI before versioning, release-ci-gate.test.ts:CI is one sequential pull-request job, release-ci-gate.test.ts:one build is reused by crate tests, check, and package tests, release-ci-gate.test.ts:reference check uses workspace packages not npm
prerelease_tests
reqlan rq/distribution/distribution.rq
JS / TS package tests ( `pnpm run test:js` ) run after the shared TypeScript compile ( `pnpm run build:tsc` ) from this git checkout.
GitHub CI runs them in the same job as crate tests and check, after that compile ( ci_gate ).
This job runs on every pull request and on main before versioning.
Host native addon is required because analytical and language tests load `reqlan-napi`.
The host release build compiles `reqlan-napi` only. Crate tests compile `reqlan-lsp`. That binary ships in the VSIX, not in this host package.
Azure runs `pnpm run test:js` before VSIX publish ( extension_distribution ).
Local `pnpm run test` runs `test:js` then `test:rust` ( rust_crate_layout ).
The implementation lives in ci.yml; release.yml calls it with `workflow_call` as part of ci_gate.
Related: check_meta_implementation
- implementation
- ci.yml, release.yml, package.json
- status
- done
- tests
- release-ci-gate.test.ts, release-ci-gate.test.ts:one build is reused by crate tests, check, and package tests, release-ci-gate.test.ts:pnpm test runs crate tests, release-ci-gate.test.ts:TypeScript compile generates Langium sources first
release_tagging
reqlan rq/distribution/distribution.rq
Deployment is tag-driven rather than commit-driven for every publishable channel.
Tags are created automatically by deployment_flow, not manually.
Site deployments are triggered by Git tags matching `site/v*` via site_distribution.
VS Code extension publishing is triggered by Azure DevOps tags matching `ext/v*` via extension_distribution and openvsx_registry.
npm publishing is triggered by Git tags matching `language/v*`, `analytical/v*`, `cli/v*`, or `mcp/v*` via npm_distribution.
Platform native packages ride `analytical/v*` ( same version as `@reqlan/analytical` ); they are not a separate tag prefix.
The tag suffix after the channel prefix ( `site/v`, `ext/v`, `language/v`, `analytical/v`, `cli/v`, `mcp/v` ) equals the package. json version at that tag.
npm_package_readme
reqlan rq/distribution/distribution.rq
Publishable npm packages ( `@reqlan/language`, `@reqlan/analytical`, `@reqlan/cli`, `@reqlan/mcp` ) ship README. md generated from each package's `README.template.md`.
Pattern matches extension_readme: centered logo, package name, description, features, phonebook links, and Changesets changelog body.
Generated by generate-npm-package-readmes.ts via root `pnpm run build:readme`.
Contact, Discord, sponsorship, and repository links come from phonebook via phonebook.ts per npm_package_readme_links.
CLI native-engine install note: published_host_native_install.
- status
- done
extension_readme
reqlan rq/distribution/distribution.rq
The VSIX package must include a README for the Marketplace and Open VSX listings.
Contact, Discord, sponsorship, and repository links come from phonebook via phonebook.ts per extension_readme_links.
Release notes are appended from CHANGELOG.md, which Changesets maintains per version_management.
Generated during extension build from README.template.md by generate-readme.ts per extension_readme_build.
root_readme
reqlan rq/distribution/distribution.rq
The GitHub repository README is the primary repo lander per landers.
Site, marketplace, repository, Discord, sponsorship, and contact links come from phonebook via phonebook.ts per root_readme_links.
Generated from README.template.md by generate-root-readme.ts.
vsix_native_not_from_npm
reqlan rq/distribution/distribution.rq
Azure must not use the npm deploy path as an input when it packs VSIXes.
Git at the `ext/v*` tag is canonical. Azure compiles the native_targets matrix from that commit ( vsix_export, extension_distribution ).
npm stays the install path for CLI and MCP only ( npm_distribution, rust_binary_distribution ).
- history
- First native VSIX design: GitHub Actions compiled napi on `analytical/v*`, published platform packages, and Azure fetched `--latest` from npm.
Azure did not compile Rust.
That design treated npm as a hand-off between the two pipelines.
After a changeset release, platform packages stayed on the previous patch (received `1.11.0`) while analytical and the extension moved (expected `1.11.1`).
native-packaging.test.ts failed on that mismatch.
The lag is structural: `changeset version`, a glob in the Changesets `fixed` group, and a registry wait are not one atomic git snapshot.
Decision: keep npm for CLI and MCP; compile the matrix in Azure from git for VSIX. - justification
- Marketplace version is `reqlan-extension` package.json and can differ from `@reqlan/analytical` (version_management).
Azure compiles the six host binaries from that `ext/v*` commit (`build_native` in azure-pipelines.yml).
The VSIX then contains the engine that matches the extension checkout, not a different `@reqlan/analytical` npm tarball. - negative
- Do not feed npm_distribution into Marketplace or Open VSX packaging.
Do not wait for an `analytical/v*` tag, and do not poll `npm view` or `npm pack` (`scripts/fetch-native-packages.mjs --latest`).
That path couples two tag channels and two clocks.
Changesets can bump `@reqlan/analytical` and `reqlan-extension` independently (version_management).
`--latest` then packs a different `@reqlan/analytical` semver than the `ext/v*` tag, or the pipeline waits on packages that are not on the registry yet. - status
- done
vsix_export
reqlan rq/distribution/distribution.rq
One VSIX is built per native_targets tuple via `vsce package --target <tuple> --no-dependencies`.
Each VSIX keeps today's esbuild-bundled JS ( TS dependency graph stays bundled ); only the matching platform native package is staged into the VSIX so other targets' binaries are excluded.
The same VSIX packs `bin/reqlan-lsp` for that target ( language_server_rust ). Azure `collect-napi-binary.mjs --with-lsp` copies that binary into the native artifact. The pack script checks that zip entry by `file_size`. It does not read the binary through a pipe. The napi addon stays for the index host. npm platform packages do not contain it ( rust_binary_distribution ).
Stamp `targetPlatform` so Marketplace / Open VSX route by extension host ( extension_host_target, native_host_binary_distributed ).
Artifact name shape: `reqlan-extension-<version>-<target>.vsix`.
The VSIX includes logo assets from the extension media build: PNG for marketplace icon, language file icon, activity bar, and README; WebP as a raster fallback.
Implementation: package-extension-targets.mjs, prepare-native-packages.mjs, collect-napi-binary.mjs, .vscodeignore ( `native/`, `bin/` ), azure-pipelines.yml.
- plan
- goal
Ship six host-targeted VSIXes, each containing only the core engine `.node` for that extension-host platform.
constraints
- Keep --no-dependencies for the bundled TS graph; stage only the matching native package.
- Git at the `ext/v*` tag is canonical (vsix_native_not_from_npm). Azure compiles the native_targets matrix from that commit and packs those binaries.
- npm platform packages remain a CLI/MCP install path on `analytical/v*` (npm_distribution / rust_binary_distribution). They are not an input to Azure.
- `vscode:prepublish` must not restage the host native addon (`--skip-native`); each VSIX `native/target.json` must equal that VSIX `--target`.
steps
1. Stage matching `@reqlan/analytical-<platform>-<arch>` into extension `native/` before vsce. (done)
2. Package with `vsce package --target <tuple> --no-dependencies` for each vsix_export entry; skip native restage in vscode:prepublish; verify packed `native/target.json`. (done)
3. Compile the native_targets matrix in Azure and prepare packages from git versions + those artifacts. (done)
4. Publish each target to Marketplace and Open VSX (extension_distribution, openvsx_registry). - status
- in-progress
- todo
- first ext/v* release with six target VSIXes not yet shipped
site_distribution
reqlan rq/distribution/distribution.rq
GitHub Pages deployment runs only when an `site/v*` tag is pushed.
Tags are created by deployment_flow; the site workflow does not deploy on ordinary commits.
The static build embeds `/spec` via spec_html_export, which needs the host `reqlan-napi` binary.
The site workflow therefore builds and stages the host native engine ( `scripts/stage-host-native.mjs` with `REQLAN_FORCE_NATIVE_BUILD=1` ) before `pnpm run build`.
The implementation lives in deploy-site.yml.
extension_distribution
reqlan rq/distribution/distribution.rq
Azure DevOps builds, tests, packages, and publishes the VS Code extension only for tags matching `ext/v*`.
Tags are created by deployment_flow.
The extension version comes from packages / extension / package. json at the tag; the pipeline must not overwrite it from the tag suffix.
The implementation lives in azure-pipelines.yml.
The pipeline builds language, packages, and the extension only; it does not run the site static build or install Playwright ( site_distribution owns site CI ).
Native core-engine binaries for VSIX come from the Azure `build_native` matrix on this git tag ( vsix_native_not_from_npm, rust_binary_distribution, vsix_export ). GitHub Actions still builds and publishes platform packages on `analytical/v*` for CLI / MCP ( npm_distribution ).
Before tests Azure stages matrix artifacts into workspace packages ( `prepare-native-packages.mjs --binary-dir` ) and checks the host optionalDependency ( `scripts/ensure-host-native.mjs --no-build` ).
VSIX packaging follows vsix_export: one VSIX per native_targets tuple; Marketplace selects the VSIX matching the extension-host target ( extension_host_target ).
Marketplace publish is complemented by Open VSX per openvsx_registry.
Pipeline cache and publish parallelism: extension_pipeline_cache, extension_pipeline_publish.
- status
- in-progress
- todo
- first multi-target Marketplace publish not yet run
extension_pipeline_cache
reqlan rq/distribution/distribution.rq
Azure `build_native` mirrors GitHub `Swatinem/rust-cache` via `Cache@2`: cache rustup + cargo home under `$(Pipeline.Workspace)/rust-cache` ( `CARGO_HOME` / `RUSTUP_HOME` ) and `crates/target`, keyed by OS, `rustTarget`, and `crates/Cargo.lock`.
Install rustup only when `$CARGO_HOME/bin/rustc` is missing after restore; otherwise reuse the cached toolchain ( `--no-modify-path` ).
Azure `build_test_package` caches the pnpm store keyed by OS and `pnpm-lock.yaml` ( same role as `cache: pnpm` on GitHub ).
Do not cache VSIX or napi pipeline artifacts across tags; git at `ext/v*` stays canonical ( vsix_native_not_from_npm ).
Implementation: azure-pipelines.yml.
Related: extension_distribution, ci_gate ( GitHub rust-cache + pnpm ).
- status
- done
- tests
- native-packaging.test.ts, native-packaging.test.ts:Azure extension pipeline caches rust and pnpm and publishes in parallel
extension_pipeline_publish
reqlan rq/distribution/distribution.rq
Marketplace and Open VSX publish every per-target VSIX in parallel ( `ForEach-Object -ThrottleLimit 6 -Parallel` ), not one after another.
Open VSX uses the workspace `ovsx` package ( `pnpm --filter./packages/extension exec ovsx` ); do not `pnpm dlx ovsx` per file.
Local `--openvsx` in package-extension-targets.mjs uses the same `pnpm exec ovsx` path.
Implementation: azure-pipelines.yml, package.json, package-extension-targets.mjs.
Related: extension_distribution, openvsx_registry, vsix_export.
- status
- done
- tests
- native-packaging.test.ts, native-packaging.test.ts:Azure extension pipeline caches rust and pnpm and publishes in parallel
openvsx_registry
reqlan rq/distribution/distribution.rq
The extension should be published to the Open VSX registry at https://open-vsx.org so it is installable in editors that use Open VSX instead of the Visual Studio Marketplace.
Publishing should use the same tag-driven `ext/v*` releases as extension_distribution.
Each per-target VSIX from vsix_export is published to Open VSX ( Marketplace and Open VSX both select by extension-host `targetPlatform` ).
Azure DevOps is the authoritative publish workflow; Open VSX publish belongs in azure-pipelines.yml alongside marketplace deploy.
Publish path follows extension_pipeline_publish.
- status
- in-progress
- todo
- first multi-target Open VSX publish not yet run
workflow_deduplication
reqlan rq/distribution/distribution.rq
Extension publish automation should have a single authoritative workflow to avoid duplicate marketplace releases.
Azure DevOps is the authoritative extension publishing workflow per extension_distribution and openvsx_registry.
The site remains deployed by GitHub Actions per site_distribution.
npm packages are published by GitHub Actions per npm_distribution.
Versioning and tag creation are owned by GitHub Actions per deployment_flow.
grammar_linguist
reqlan rq/distribution/distribution.rq
The grammar should be updated to use
https://github.com/github-linguist/linguist
Acceptance is dependent on maturity and usage.
( this is what gh uses for language rendering etc )
- status
- pending
landers
reqlan rq/distribution/landers.rq
The reqlan extension has the following entry points:
- the vsc marketplace and open vsx marketplace via the README.template.md
- npm packages via README.template.md, README.template.md, README.template.md, and README.template.md
- the site.
- the github repository via the README.template.md
- the GitHub sponsor button via github_funding
- landers must keep cross references up to date via the phonebook.ts
phonebook
repo_license
reqlan rq/distribution/license.rq
The repository root must declare the same licence as the publishable packages and crates.
SPDX id: `AGPL-3.0-only`.
The root must hold a `LICENSE` file with the GNU Affero General Public License version 3 text.
The extension package `LICENSE` must use the same text as the root `LICENSE`.
Package metadata must set `"license": "AGPL-3.0-only"` for the workspace root and for every publishable package under `packages/`.
The Rust workspace must set `license = "AGPL-3.0-only"` in Cargo.toml.
- implementation
- LICENSE, package.json, LICENSE, Cargo.toml
- status
- done
- tests
- repo-license.test.ts, repo-license.test.ts:root LICENSE is AGPL-3.0 and matches extension LICENSE, repo-license.test.ts:publishable packages and crates declare AGPL-3.0-only
native_host_binary
reqlan rq/distribution/native_host_binary.rq
Select the native core-engine binary from the extension host.
The host is the Node process that runs the extension.
Read `process.platform` and `process.arch` from that process.
Do not use the platform of the VS Code UI client.
Examples:
- UI on Windows and host on Linux SSH: use a linux tuple.
- UI on Windows and host on WSL: use a linux tuple.
- UI and host on macOS: use a darwin tuple.
Map the platform and the arch to one tuple in native_targets.
Load only the binary that matches that tuple.
Do not load a binary for a different tuple.
If the platform and the arch are not in native_targets, fail.
If the binary is missing, fail. Do not use sql. js.
Keep the loader map the same as native-targets.mjs.
Local development: native_host_binary_development.
Production distribution: native_host_binary_distributed.
Implementation: load-native.ts.
- status
- done
native_host_binary_development
reqlan rq/distribution/native_host_binary.rq
Use this procedure on a developer machine ( F5 and `pnpm run build` ).
Identify the host from `process.platform` and `process.arch` of the build process.
The build process and the extension host must be the same machine.
Copy the matching `.node` file to `packages/extension/native/reqlan_napi.node`.
Write `packages/extension/native/target.json` with the host tuple.
If the binary is not present, build it with `cargo build -p reqlan-napi -p reqlan-lsp --release`.
At run time, search in this order:
1. The `native/` folder of the extension, if `target.json` records the host tuple.
2. The resolved `main` of the host npm package ( `createRequire` from `@reqlan/analytical/package.json` ).
3. The host file in `packages/analytical-native/<napiSuffix>/` ( workspace package directory, same layout as a published package ).
4. The host npm package name.
5. `crates/target/<rustTarget>/release` and `crates/target/release`.
6. The debug folders with the same names.
Do not search packages for other platforms.
If `target.json` records a different tuple, do not load `native/reqlan_napi.node`.
Windows cargo emits `reqlan_napi.dll`; the loader uses `process.dlopen` for `.dll` and `.node` ( Node `require` only loads `.node` ).
Windows UI with a WSL extension host uses the linux tuple ( native_host_binary ).
Windows UI with a Windows extension host cannot load a `.node` staged from WSL; restage on Windows or open the folder in a WSL remote window.
Before tests, the workspace host package must contain the `.node` so loaders behave like production ( native_host_binary_distributed ). `scripts/ensure-host-native.mjs` uses an existing matrix binary, or cargo locally.
Azure compiles the native_targets matrix from git and stages those artifacts; it does not fetch binaries from npm.
Detail: extension_host_native_stage.
Implementation: stage-host-native.mjs, ensure-host-native.mjs, index.ts.
- status
- done
native_host_binary_distributed
reqlan rq/distribution/native_host_binary.rq
Use this procedure for a published VSIX and for published npm packages.
VS Code extension:
The registry installs the VSIX that has `targetPlatform` equal to the extension host.
Each VSIX contains one `.node` file for one native_targets tuple.
The file name is `native/reqlan_napi.node`.
The VSIX also contains `native/target.json`.
At run time, read `process.platform` and `process.arch` on the extension host.
If `target.json` records a different tuple, do not load `native/reqlan_napi.node`.
Do not put binaries for other platforms in that VSIX.
The Azure pipeline compiles each platform binary from this git commit ( `build_native` + `collect-napi-binary.mjs` + `prepare-native-packages.mjs --binary-dir` ). Package versions in git are canonical. The pipeline does not wait for npm.
Related: vsix_export, extension_distribution, vsix_native_not_from_npm.
CLI and MCP:
npm installs the host package from `optionalDependencies` on the published `@reqlan/analytical` tarball.
Git does not list those entries. prepare-native-packages.mjs `--publish-versions` writes them at npm publish.
The loader resolves that package from `@reqlan/analytical/package.json` ( `createRequire` ), which is where the optional dependency is attached after `npm install`.
Published installs also run published_host_native_install.
Related: rust_binary_distribution, native_bridge.
Implementation: package-extension-targets.mjs, prepare-native-packages.mjs, load-native.ts, check-host-native.mjs, azure-pipelines.yml.
- status
- in-progress
- todo
- first multi-target VSIX and platform packages not yet published
published_host_native_install
reqlan rq/distribution/native_host_binary.rq
After a published install of `@reqlan/analytical`, the host platform package must resolve.
The host is `process.platform` and `process.arch` of the install process ( native_host_binary ).
Git `@reqlan/analytical` does not list `optionalDependencies`. The check exits 0 in this workspace.
The published tarball lists pinned optionalDependencies ( rust_binary_distribution ).
That tarball runs check-host-native.mjs as `postinstall`.
If the host package name is missing from `optionalDependencies`, or `createRequire` from `@reqlan/analytical/package.json` cannot resolve that package to a file, the script prints a warning and exits 0.
The warning text tells the user how to enable optional dependencies and how to limit pnpm to the host OS and CPU.
Do not use `--force`. `--force` installs every optional platform package.
Do not skip the script with `--ignore-scripts` on a published install.
CLI install documentation: README.template.md.
Implementation: check-host-native.mjs, package.json, README.template.md, README.template.md.
- status
- done
- todo
- postinstall warning is not covered by automated tests; package-manager optional install is not a reliable unit-test guarantee
docs_reqs
reqlan rq/docs/docs.rq
Project requirements should all be documented in the the reqlan rq folder of this repo.
export_docs_tag
reqlan rq/docs/docs.rq
The " @ docs " tag should be used to mark files as included in the docs.
docs_image_generation
reqlan rq/docs/docs.rq
Images of HTML components for docs, READMEs, and slide packs are generated at build time from production UI.
Prefer live HTML imported from production code when embedding is practical; otherwise capture PNGs from the same bundles.
Deck asset keys are owned by tutorials.rq".presentation_assets.
Pipeline: docs_webview_build → docs_playwright_capture → sync_presentations.
- implementation
- capture.mts, build-static.mts
- status
- done
docs_webview_build
reqlan rq/docs/docs.rq
The site static build builds the extension webviews needed for docs captures before Playwright runs.
Builds only the webviews listed by the capture catalog ( activity-bar, ideas-summary, onboarding ) — not a full extension VSIX.
Uses the same Vite configs as webview_build.
- implementation
- build-webviews.ts, vite.config.ts, vite.config.ts, vite.config.ts
- status
- done
docs_playwright_capture
reqlan rq/docs/docs.rq
Playwright loads each built webview via a harness page with a mocked `acquireVsCodeApi` host,
posts demo index / context payloads, and writes PNGs into assets.
Generated assets replace the former coloured SVG stubs ( activity-bar, montage-ide, chat-search, file-link ).
Wait for document load, then the shot ready selector. The Ideas Summary montage shot waits longer because the bundle is large.
On a ready-selector timeout, print page errors and `#app` HTML.
Runs as a step in build-static.mts before presentation sync.
CI installs Chromium via `pnpm exec playwright install --with-deps chromium`.
- implementation
- capture.mts, catalog.ts, write-harnesses.ts, PresentationPlayer.tsx
- status
- done
chat_participant
reqlan rq/extension/agent/chat-participant.rq
the chat participant module should expose @ reqlan in vscode chat.
it should consume analysis functions from the analytical submodule rather than duplicating graph logic.
slash commands should use the rq- prefix only in chat, e. g. rq-search, rq-context, rq-graph, and rq-related for the active file.
chat_participant_completion
reqlan rq/extension/agent/chat-participant.rq
file and requirement references should be code completed in the chat window via # file and # requirement language model tools.
mcp
reqlan rq/extension/agent/chat-participant.rq
Cursor and other non-VS-Code clients use the MCP server ( `@reqlan/mcp` ).
Search and retrieval on that server use mcp_click_retrieval only.
Reference checks use mcp_check.
The MCP tool set is not a 1: 1 wrap of every @ reqlan chat slash command.
Published to npm per npm_distribution.
Cursor project config lives in mcp.json and skills sync to skills via scripts / sync-cursor-ai. mjs.
chat_participant_skills
reqlan rq/extension/agent/chat-participant.rq
the chat participant must not have duplicate skills.
ai_api
reqlan rq/extension/agent/features-ai.rq
should use the chat participant api. which should be in a module. that consumes analysis functions from other modules. https://code.visualstudio.com/api/extension-guides/ai/chat
ai_integration
reqlan rq/extension/agent/features-ai.rq
The extension should integrate with ai workflows via command palette actions and mcp tools.
Ai-facing features should prioritise token minimisation and focused context over full-graph dumps.
Command palette actions use the Reqlan category; chat slash commands and skills use the rq- prefix.
ai_build_requirement
reqlan rq/extension/agent/features-ai.rq
A command palette action ( e. g. ctrl + p: build new requirement ) should create a requirement from user or ai-provided intent.
ai_add_to_context
reqlan rq/extension/agent/features-ai.rq
A command palette action ( e. g. ctrl + p: add to context ) should add selected requirements to the ai conversation context.
ai_write_plan
reqlan rq/extension/agent/features-ai.rq
A command palette action ( e. g. ctrl + p: write plan ) should draft or update an @ plan attribute for the selected idea.
ai_fix_stale_references
reqlan rq/extension/agent/features-ai.rq
A chat skill `/rq-fix-stale-references` finds and repairs unresolved idea, comment, file, import, and wildcard references.
The issue list comes from check ( `reqlan check --json` ).
Repair choices follow import_error and comment_reference_refactor_support.
Slash-command name uses chat_skill_naming.
- implementation
- SKILL.md, register-agent-contributions.ts, package.json
- status
- done
add_to_chat
reqlan rq/extension/agent/features-ai.rq
A set of command_palette functions that add the selected idea, ideaset, or file to the chat.
Commands: Add Idea / Ideaset / File to **Current** Chat ( primary ) and to **New** Chat ( secondary ); category Reqlan.
Uses the idea / ideaset under the cursor ( or ideas overlapping the editor selection ) when in a. rq file; otherwise QuickPick.
Primary: inject `#requirement` / `#file` context into the **current** chat input without submitting.
Secondary: open a **new** chat / agent session, then seed the same payload into its input.
Discoverability: editor context uses a **Reqlan: Add to Chat** submenu ( current + new for idea / ideaset / file ). Palette titles name Current vs New explicitly.
Host APIs ( Cursor vs VS Code ) — see open-chat helper:
- Cursor: `workbench.action.chat.open` always creates a **new** tab ( `openInNewTab: true` ); do **not** use it for current-chat.
Current = `composer.focusComposer` + paste; New = `composer.createNew({ openInNewTab: true, partialState: { text, richText } })`.
- VS Code Copilot: current = `workbench.action.chat.open` + `isPartialQuery: true`; new = `workbench.action.chat.newChat` then open.
Clipboard fallback when no chat command is available.
Host open helper: open-chat.ts ( `target: 'current' | 'new'` ).
Activity bar search hits: search_add_to_chat — split button with ▾ menu.
- implementation
- register-ai-commands.ts, open-chat.ts, package.json
- status
- done
mcp_tools
reqlan rq/extension/agent/skills-and-mcp.rq
The MCP server ( `@reqlan/mcp`, server.ts ) exposes a small tool set for AI clients.
Search and retrieval use mcp_click_retrieval only.
Reference checks use mcp_check.
Idea diffs use mcp_diff.
Do not expose parse, search, list, file context, local graph, summarise subtree,
requirement_reference, file_reference, or list_interactions as MCP tools.
Those operations stay on AnalysisApi and CLI when they exist.
Headless index storage follows application_memory ( `<base>/.reqlan` ), shared with the extension and CLI.
- implementation
- server.ts
- status
- done
- tests
- server.test.ts, server.test.ts:MCP surface is click, check, diff, completion_status, and prompt
mcp_check
reqlan rq/extension/agent/skills-and-mcp.rq
MCP `check` wraps check for AI clients ( server.ts ).
The tool returns JSON issue rows in check_order_by_target order.
An empty list means that there are no issues.
Optional arguments match the CLI mcp_check flags: glob, wildcard-zero, wildcard-one, skip-targets, and skip-gitignored-targets.
`glob` is one path pattern or a list of path patterns ( check_glob_patterns ).
A file that matches any pattern is in the scan.
Related: mcp_tools check check_unresolved_imports
- implementation
- server.ts
- status
- done
- tests
- server.test.ts:MCP surface is click, check, diff, completion_status, and prompt, server.test.ts:check returns JSON issue rows
mcp_diff
reqlan rq/extension/agent/skills-and-mcp.rq
MCP `diff` wraps diff for AI clients ( server.ts ).
Arguments are optional `from`, optional `to`, and optional `verbosity` ( diff_verbosity ).
The tool returns the same JSON array as `reqlan diff --json`.
An empty array means that no idea changed.
A missing revision is a tool error.
Related: mcp_tools mcp_diff
- implementation
- server.ts
- status
- done
- tests
- server.test.ts:MCP surface is click, check, diff, completion_status, and prompt, server.test.ts:diff returns created JSON and text bodies, server.test.ts:omitted targets follow the clean and dirty defaults, server.test.ts:a bad revision is a tool error
mcp_click_retrieval
reqlan rq/extension/agent/skills-and-mcp.rq
MCP `click` is the canonical search and retrieval tool ( click, server.ts ).
One tool returns compact unique context, ranked ambiguous matches, or search hits.
A second click on the same centre in the session returns connected content ( agent_advisory ).
This surface maximises the token-to-insight ratio: names, short bodies, and caps — not edge dumps or full-graph lists.
Keyword search, file context, local graph, and subtree expansion are click paths, not extra MCP tools.
Agents must pass `sessionKey` on the next click.
Related: mcp_keyword_search, mcp_tree_interrogation, mcp_tree_summarisation.
- status
- done
- tests
- server.test.ts:MCP surface is click, check, diff, completion_status, and prompt, click.test.ts:click API returns session key and unique then revisit
mcp_tools_prompt
reqlan rq/extension/agent/skills-and-mcp.rq
An mcp tool may provide a prompt-oriented entry point for working with the requirement graph.
That tool must call mcp_click_retrieval for search and retrieval. It must not call the removed tools.
- implementation
- server.ts
- status
- done
- tests
- server.test.ts:MCP surface is click, check, diff, completion_status, and prompt
mcp_keyword_search
reqlan rq/extension/agent/skills-and-mcp.rq
Keyword search across idea names, bodies, and attributes is a click path when no centre matches.
Do not expose a separate MCP search tool.
- implementation
- mcp_click_retrieval, click
- status
- done
- tests
- server.test.ts:MCP surface is click, check, diff, completion_status, and prompt, click.rs:click_falls_through_to_search_when_nothing_matches
mcp_tree_interrogation
reqlan rq/extension/agent/skills-and-mcp.rq
File and idea neighbourhoods are a click unique result ( outbound, backlinks, siblings ).
Do not expose a separate MCP file-context or local-graph tool.
- implementation
- mcp_click_retrieval, click
- status
- done
- tests
- server.test.ts:MCP surface is click, check, diff, completion_status, and prompt, click.rs:click_returns_unique_idea_without_edges, click.rs:click_code_file_returns_backlinks_and_comment_refs
mcp_tree_summarisation
reqlan rq/extension/agent/skills-and-mcp.rq
Compact subtree context is a click revisit: connected content for a centre already clicked in the session.
Do not expose a separate MCP summarise-subtree tool.
- implementation
- mcp_click_retrieval, click
- status
- done
- tests
- server.test.ts:MCP surface is click, check, diff, completion_status, and prompt, click.rs:click_revisit_returns_connected_content
mcp_interaction_discovery
reqlan rq/extension/agent/skills-and-mcp.rq
MCP clients discover tools through the MCP protocol tool list.
Do not expose a list_interactions MCP tool.
- implementation
- server.ts
- status
- done
- tests
- server.test.ts:MCP surface is click, check, diff, completion_status, and prompt
skill_namespace_references
reqlan rq/extension/agent/skills-and-mcp.rq
backslash references to skills based on the namespace should be supported.
cursor_skills_install
reqlan rq/extension/agent/skills-and-mcp.rq
A command palette action ( e. g. ctrl + p: reqlan install cursor skills ) should copy rq-* skills from the extension into the workspace. cursor / skills folder and update. cursor / mcp. json.
Prefer the workspace `packages/mcp/bin/mcp.js` when present; otherwise `npx -y @reqlan/mcp` from npm_distribution.
Place in install sequencing ( workspace agent files, not `.reqlan` ): workspace_agent_files.
chat_skill_naming
reqlan rq/extension/agent/skills-and-mcp.rq
Cursor and Copilot chat skills and slash commands should use the rq- prefix, e. g. rq-search and rq-build-requirement.
This prefix must not appear in command palette titles; palette entries use category Reqlan only.
extension_product
reqlan rq/extension/extension.rq
The VS Code / Cursor extension is the editor product for the reqlan requirement graph.
It is not the language definition ( language_package ), the index engine
( analytical_package ), or the headless MCP / CLI.
Host entry: main.ts. Product bound: vscode_extension, lsp_support.
Event-driven host mindset: event_driven.
Domains nest under extension_domains. Surfaces for extension_surfaces
point at these domain hubs — not a flat bag of features-* files.
Composition root: main.ts registers domain modules after the index adapter activates.
- status
- done
host_lifecycle
reqlan rq/extension/extension.rq
Install vs base, activation, first paint, onboarding, and configuration schema contribution.
installation, activation, extension_startup_reliability,
installation_event, configuration_location,
command_palette.
- status
- done
language_surface
reqlan rq/extension/extension.rq
Edit-time intelligence in the text editor: LSP client glue, syntax, imports, comment `rq:…`,
CodeLens, inlays, and code actions.
syntax_features, features-imports.rq, code_actions,
references_in_functional_code_comments.
- status
- done
index_host
reqlan rq/extension/extension.rq
Thin VS Code adapter over `@reqlan/analytical`: watchers, Uri helpers, multi-base routing,
idle stale checks, git-date fill, and index diagnostics webview.
Engine ownership stays in the indexer; see application_memory,
graph-analysers.rq, index_diagnostics, git-codelens.rq.
- status
- done
local_context
reqlan rq/extension/extension.rq
Editor-adjacent Context sidebar and the composed context model.
Chrome and pane catalog: activity_bar.
Model: context_scope; evolution: context_scope_v2
( not a sibling product surface ).
- status
- done
workspace_summary
reqlan rq/extension/extension.rq
Ideas Summary — workspace-wide ontology tabs, graph, timeline, and index health.
ideas_summary.
- status
- done
presentation
reqlan rq/extension/extension.rq
Shared webview discipline and the cytoscape graph library. Not a user-facing product feature.
webview, graph_library.
- status
- done
agent_surface
reqlan rq/extension/extension.rq
`@reqlan` chat, LM tools, Cursor skills, and MCP install / wrap ( MCP package stays separate ).
chat_participant, ai_integration, skills-and-mcp.rq.
- status
- done
graph_mutation
reqlan rq/extension/extension.rq
Create / split / merge / copy, file-move hooks, and idea refactor.
mutation-hooks.rq, refactor_changes.
- status
- done
export_surface
reqlan rq/extension/extension.rq
One export webview over analytical writers ( HTML, Markdown, JSON, CSV, PDF ).
export_webview.
- status
- done
extension_domains
reqlan rq/extension/extension.rq
Ideaset (extension_domains)
activation
reqlan rq/extension/host/activation.rq
VS Code loads the extension host entry at main.ts when an activation event in package.json matches.
The exported `activate(context)` function is the single activation entry point for vscode_extension.
Install-time and first-run sequencing across extension vs base layers: installation_sequencing.
Startup failure diagnosis, first-paint sequencing, bundle splitting, and development-host lessons: startup-performance.rq.
activation_events
reqlan rq/extension/host/activation.rq
Activation is declared in `contributes.activationEvents` in package.json.
- `onStartupFinished` — activate after the workbench finishes starting; ensures first-run onboarding can run without opening a `.rq` file first.
- `onLanguage:reqlan` — activate when a reqlan document is opened.
- `onLanguage:python`, `onLanguage:javascript`, `onLanguage:typescript`, `onLanguage:typescriptreact` — activate for comment-reference and glue-semantics support in those languages.
- `onView:reqlan.activityBar` — activate when the reqlan activity bar view is opened.
- `onChatParticipant:reqlan.reqlan-extension` — activate when the @ reqlan chat participant is used.
- `onCommand:reqlan.*` — activate when listed reqlan palette commands run before the extension has loaded.
There is no separate `onInstall` hook; install-time behaviour runs on the first activation after install.
activation_sequence
reqlan rq/extension/host/activation.rq
`activate` is synchronous and non-blocking in main.ts; it never awaits startup work so the UI is available as soon as possible. It runs the following phases:
1. Register reference inlay-hint and CodeLens configuration / commands synchronously.
2. Call analytical_submodule_activation — registers commands, activity bar, chat, webviews, AI commands, and mutation hooks synchronously and returns without starting indexing.
3. Register import-error quick-fix commands when the analytical submodule registered.
4. Arm first_paint_startup so index startup cannot race the activity-bar shell.
5. Invoke onboarding_check without awaiting it, so onboarding cannot block activation.
Submodule failures are logged and do not prevent later phases from running.
background_startup
reqlan rq/extension/host/activation.rq
Startup work that must not block activation is coordinated by `scheduleBackgroundStartup` in main.ts.
- first_paint_startup gates index discovery and sync when the Context view opens; a three-second fallback preserves warm startup when the sidebar remains closed.
- The language client starts after the same paint signal when the Context view opens, with a one-second fallback so language features still start when the sidebar remains closed.
- Registers attribute and name catalog sync once the language client exists; the initial push covers an already-ready index and the catalog-update subscription covers indexes that become ready afterwards.
Index and language-client failures are logged and do not affect the already-available UI.
first_paint_startup
reqlan rq/extension/host/activation.rq
The activity-bar HTML shell is assigned by activity-bar-webview-provider.ts after one event-loop turn ( retry once on invalid-state ).
Host `postMessage` starts only after the webview `ready` handshake; disposed / invalid-state errors are swallowed by safe-webview-post.ts.
Its Svelte app installs the host message listener before mount, then sends the one-shot `ready` handshake from a task queued after its first animation frame.
startup-gate.ts resolves that handshake once; `IndexService.activate` then discovers bases and syncs. If no view opens, a bounded three-second fallback starts the index without any visible first paint to contend with.
Index open / sync requires the host-matching core engine ( rusqlite ); missing `.node` fails activate.
Windows claim / dispose races: webview_claim_race.
- status
- done
- tests
- "../../../packages/extension/test/startup-gate.test.ts", "../../../packages/extension/test/safe-webview-post.test.ts", "../../../packages/analytical/src/index-store/workspace-index.ts"
analytical_submodule_activation
reqlan rq/extension/host/activation.rq
Analytical submodule registration is implemented in index.ts.
`activateAnalyticalSubmodule` is synchronous: VS Code contributions ( commands, activity bar provider, chat participant, webviews, AI commands, mutation hooks ) register synchronously and it returns the submodule immediately.
It does not start indexing; it passes the activity-bar post-paint callback into the provider and the caller starts index activation through first_paint_startup.
onboarding_check
reqlan rq/extension/host/activation.rq
Post-install onboarding is checked on every activation, not via a dedicated install event.
installation_event_trigger is satisfied because `activate` always schedules open-thanks-for-installing.ts after the activity-bar paint gate or 400 ms ( webview_claim_race ).
The check reads global state key `onboarding` via onboarding-state.ts:
- `onboardingMessageShown` — when false, open the onboarding webview panel via onboarding-panel.ts.
- `lastVersion` — updated each activation after the message has been shown so future releases can detect extension updates.
The call is fire-and-forget; errors are logged and do not fail activation.
Command-palette Show Onboarding remains immediate.
event_driven
reqlan rq/extension/host/architecture.rq
the application should be event driven.
state_machine_mindset
reqlan rq/extension/host/architecture.rq
The application should be designed as a collection of state machines.
The core index lifecycle FSM lives in the Rust runtime ( native_bridge ); Svelte
webview UI follows ui_state_management and zustand_boundary
( runes AppState, no zustand ). No JS zustand stores remain.
configuration_location
reqlan rq/extension/host/configuration.rq
An optional `.reqlan/config.json` may appear under a base's `.reqlan` directory.
For a given `.rq` file, the applying base is the nearest ancestor directory that owns a `.reqlan` folder.
The applying config is that base's `.reqlan/config.json` when present.
If the owning base has no `config.json`, or no owning base is found, defaults from configuration_import_roots apply.
A child base does not inherit a parent base's config.
- implementation
- reqlan-path-resolve.ts, path_resolve.rs
- tests
- config.test.ts:returns undefined when no config exists, config.test.ts:loads config from the owning base .reqlan, config.test.ts:loads config from an ancestor base, config.test.ts:nearest base config wins over farther ones, config.test.ts:owning base without config does not inherit parent, config.test.ts:resolveRqConfig uses defaults when no applying file exists, path-resolve.test.ts:loads importRoots list from nearest base config, path_resolve.rs:missing_import_roots_uses_default_alias, path_resolve.rs:relative_root_resolves_against_base
configuration_schema_file
reqlan rq/extension/host/configuration.rq
The machine-readable JSON Schema for `.reqlan/config.json` is config.schema.json.
That file is the single authoring source. Its `$id` is the public URL `https://reqlan.com/schemas/v1/config.schema.json`.
Path segment `v1` is schema compatibility version: additive keys stay on `v1`; breaking shape changes introduce `v2` and a new seed URL.
The site hosts a synced copy under `/schemas/v1/` ( sync_config_schema ).
The extension contributes the local schema for `**/.reqlan/config.json` via `jsonValidation` in package.json ( offline editor path ).
New bases seed `$schema` to the public `$id` ( base_config_seed ).
`.reqlan/config.json` is a JSON object. Unknown properties are not part of the schema and are ignored when loading. `$schema` is an allowed property.
- implementation
- config.schema.json, package.json, ignore.rs, sync-config-schema.mts
- status
- done
- tests
- config.test.ts:unknown properties are ignored while known keys still apply, config.test.ts:schema file documents importRoots mappings, config.test.ts:schema $id matches public v1 host path
configuration_import_roots
reqlan rq/extension/host/configuration.rq
`importRoots` is an optional array of alias-to-directory mappings in `.reqlan/config.json`.
Each mapping has:
- `alias` ( required non-empty string ): prefix before `/` in aliased import paths.
- `root` ( optional non-empty string ): directory for that alias.
A relative `root` resolves against the base root ( the parent of `.reqlan` ), not against the `.reqlan` directory.
An absolute path or `file://` URI is used as that alias' import-root directory directly.
When `root` is omitted for a mapping, that alias uses the workspace folder that contains the `.rq` file.
When `importRoots` is omitted, empty, or has no valid entries, the default is one mapping with alias `importRootAlias` from defaults.json and no explicit root.
When several aliases could match a path, the longest alias wins.
Invalid or unreadable JSON, and a non-array `importRoots` value, fall back to defaults ( or no loaded config for discovery, then defaults at resolve time ).
Language path forms and `@/` shorthand: import_paths and configuration_import_root_alias.
Comment references in source files use the same mappings: comment_reference_import_root_alias.
Schema: configuration_schema_file. Applying file discovery: configuration_location.
Editor completion of aliased import paths: code_completion.
- implementation
- reqlan-path-resolve.ts, file-path-rewrite.ts, reqlan-completion-provider.ts, reqlan-path-completion.ts, reqlan-comment-diagnostics.ts, comment-reference-path-context.ts, register-comment-reference-links.ts, config.schema.json, path.rs, path_resolve.rs, broken.rs, sync.rs, analysis.rs, session.rs
- tests
- config.test.ts:empty object uses default alias mapping, config.test.ts:importRoots alias only overrides the alias, config.test.ts:relative root resolves against the base root, config.test.ts:absolute filesystem root is used directly, config.test.ts:Windows drive-letter root is used as a file URI not scheme c:, config.test.ts:file URI root is used directly, config.test.ts:multiple importRoots map aliases to different roots, config.test.ts:longest alias wins when mappings overlap, config.test.ts:empty string alias entries are skipped, config.test.ts:empty string root is ignored on a mapping, config.test.ts:invalid importRoots entries are skipped, config.test.ts:unknown properties are ignored while known keys still apply, config.test.ts:invalid JSON falls back to undefined load, config.test.ts:non-object JSON falls back to undefined load, config.test.ts:non-array importRoots falls back to undefined load, config.test.ts:empty importRoots array uses default alias mapping, config.test.ts:resolveRqConfig falls back to defaults when applying JSON is invalid, config.test.ts:aliased path uses relative root from applying config, config.test.ts:aliased path uses workspace folder when root is omitted, path-resolve.test.ts:loads importRoots list from nearest base config, path-resolve.test.ts:resolves using config importRoots mapping, path-resolve.test.ts:rewrite leaves aliased paths unchanged, path-resolve.test.ts:toDirectoryUri does not parse a drive letter as a URI scheme, completion.test.ts:completes import-root alias paths, comment-reference-resolution.test.ts:creates a document link for an import-root aliased comment reference, path_resolve.rs:locate_uses_import_roots_from_applying_config, broken_references.rs:check_honours_import_roots_from_applying_config, parity.rs:import_root_config_file_refs_match_check, path.rs:resolves_default_alias_against_workspace_folder, path_resolve.rs:missing_import_roots_uses_default_alias, path_resolve.rs:relative_root_resolves_against_base
configuration_rqignore
reqlan rq/extension/host/configuration.rq
Each base may define path ignore rules in `.reqlan/.rqignore` using **gitignore syntax**.
Patterns are relative to the base root ( parent of `.reqlan` ), not the `.reqlan` directory.
Owned by `@reqlan/analytical` so the CLI, MCP, and extension share one filter for discovery and indexing walks.
Built-in defaults always apply ( dependencies, venvs, build output, VCS / editor stores, `*.db3` / sqlite DBs and SQLite sidecars, binary globs per binary_ignore, files that have no comments per commentless_file_ignore, `*.secret.rq`, hidden entries, and `.reqlan/` itself ); the on-disk file adds or overrides via the same syntax, including `!` negation.
New bases seed `.reqlan/.rqignore` with those defaults ( rqignore ).
Missing or unreadable `.rqignore` still uses built-in defaults.
Location convention: configuration_location. Application memory: application_memory.
- implementation
- rqignore.ts, application-memory.ts, create-base.ts, base-discovery.ts, workspace-index.ts
- status
- done
- tests
- rqignore.test.ts, rqignore.test.ts:inverse rqignore patterns opt binary files back in, .rqignore when creating a new base, base-discovery.test.ts:skips node_modules and does not treat .reqlan as a walkable base root, workspace-index.test.ts:skips .rq files under rqignore patterns
ai_naming
reqlan rq/extension/host/configuration.rq
Command palette entries use category " reqlan " with unprefixed titles ( the palette renders them as " reqlan:... " ).
The rq- prefix is reserved for chat slash commands and agent skills only, e. g. / rq-search and / rq-build-requirement in Cursor or @ reqlan / rq-search in VS Code Copilot.
Do not put rq- or " RQ: " in command palette titles; that duplicates the visible prefix.
command_palette
reqlan rq/extension/host/features-commands.rq
Extension commands should be available via the vscode command palette and configurable keyboard shortcuts.
Command titles should not repeat the category prefix; use category " reqlan " with plain titles so the palette shows " Reqlan: List All Ideas ", not " Reqlan: Reqlan:... " or " RQ: RQ:... ".
Commands belong to product domains; this file is the palette naming hub under host lifecycle.
Agent: add_to_chat. Index host: open_index_diagnostics.
Diff: diff_webview.
Export: export_html and siblings. Mutation: refactor_support, barrel_page, decompose.
Language: search_code_actions, code_actions_ignore_error, create_idea_below_idea_containing_unresolved_reference_under_cursor.
- status
- done
view_all_requirements
reqlan rq/extension/host/features-commands.rq
A command palette action should open a browsable view of all requirements in the workspace
( ideas_summary ).
toggle_indirect_references
reqlan rq/extension/host/features-commands.rq
A command palette action should toggle display of indirect references in complementary rendering and graph views.
get_local_graph
reqlan rq/extension/host/features-commands.rq
A command palette action should get the local graph for the current file or selected idea ( local_graph_analysis ).
decompose
reqlan rq/extension/host/features-commands.rq
A command pallete action for decomposition. Should replace an idea with a reference to a new file that holds the old contents.
Should accept multiple inputs and put them in a list.
- todo
- true
exports
reqlan rq/extension/host/features-commands.rq
graph should be exportable via the export_webview and format entry ideas
( export_html, export_markdown, export_JSON,
export_csv, export_pdf ).
divide_and_conquer
reqlan rq/extension/host/features-commands.rq
A command palette action should divide and conquer the current file or selected ideaset. ( an llm prompt that takes all the context and fires off subagents )
pallete_function_create_todo
reqlan rq/extension/host/features-commands.rq
A function that opens up a modal webview form allowing the user to write a rq-idea, search for references etc, and writes it to a specified output file.
default folder is next to current file, but should be selectable in form.
This behaviour should be configurable via configuration.rq
- todo
- true
open_a_random_requirement
reqlan rq/extension/host/features-commands.rq
as it sounds
- todo
- true
search_code_actions
reqlan rq/extension/host/features-commands.rq
when cursor is in a `reference`, there shouls be a code action to search for references to that idea.
it should also allow wrapping a selected string, or the word at the cursor when in idea-body prose, as a new `reference`.
it should open up a webview modal that shows a search dialog that allows the user to search for potential references.
the search menu should preserve / show the context of the would-be reference: the rest of the containing idea, with styling, and with the selected text pulsing / styled prominently.
it should support fuzzy / partial searching via fuzzy_search. it should list the closest matches in a paginated view.
selecting the idea should fill / replace the reference ( or wrap the selection as `name` ) and an import ( if required ) appropiately
The lightbulb command ( `reqlan.searchReference` ) is arg-less because VS Code caches arg-bearing code-action commands and may dispose them on refresh ( error text like Actual command not found ).
At invoke time the extension resolves the site via LSP `reqlan/referenceSearchSite`, or a local parse of the active editor when the language client is not yet running — it must not fail with a false " language server is not ready " when a local site can be resolved.
- implementation
- reqlan-idea-reference-site.ts, reqlan-reference-search-site.ts, reqlan-code-action-provider.ts, code_actions.rs, reference-search-panel.ts, reference-search-import-path.ts, fuzzy-search.ts, native-workspace-index.ts, register-import-error-commands.ts, main.ts, main.ts
- status
- done
- tests
- code-actions.test.ts, reference-search.test.ts, extension-package.test.ts, fuzzy.rs, code_actions.rs:offers_search_code_action_when_cursor_is_inside_a_resolved_reference, code_actions.rs:offers_wrap_code_action_for_a_prose_selection, code_actions.rs:wraps_the_word_under_the_cursor_when_selection_is_empty
format_page
reqlan rq/extension/host/features-commands.rq
- set the whitespace etc appropriate for the page.
- ideating
- true
- todo
- true
barrel_page
reqlan rq/extension/host/features-commands.rq
When a `.rq` page grows large, barrel it into a container: create one sibling file per top-level idea, import those files into the current page, and replace the page body with a single container idea whose name the user chooses ( default: the sanitized file basename ).
Same-file sibling refs are rewritten to qualified imports in the child files. Existing page imports are copied into each child. Top-level ideasets are preserved in the container file.
Behaviour lives in analytical_package and is exposed via cli / commands ( `reqlan barrel` ).
Extension: file-level source code action **Barrel page into container … ** and command palette **Barrel Page** ( `reqlan.barrelPage` ) prompt for the container name, confirm, then create child files and rewrite the active page via WorkspaceEdit.
Related: file_based_code_actions decompose
- implementation
- barrel-page.ts, barrel.ts, main.ts, reqlan-code-action-provider.ts, code_actions.rs, register-barrel-page-command.ts, barrel-page-apply.ts, package.json
- status
- done
- tests
- barrel-page.test.ts:creates one child file per idea and a container defaulting to file basename, barrel-page.test.ts:writes child files and replaces the source with a container, code-actions.test.ts:offers barrel page source action when the file has top-level ideas, code-actions.test.ts:omits barrel page when only quickfix is requested or there are no ideas, code_actions.rs:offers_barrel_page_source_action_when_the_file_has_top_level_ideas, code_actions.rs:omits_barrel_page_when_only_quickfix_is_requested_or_there_are_no_ideas, barrel-page-apply.test.ts:maps child file names next to the source path, barrel-page-apply.test.ts:detects overwrite conflicts and source-self collision
file_based_code_actions
reqlan rq/extension/host/features-commands.rq
Code actions should be available for the whole file. The should include:
( regardless of cursor positions )
- barrel page — done via barrel_page ( `source.barrelPage` / `reqlan.barrelPage` )
- barrel idea
- decompose idea
- search for references.
- create idea
code_actions
- ideating
- .
- tests
- code-actions.test.ts:offers barrel page source action when the file has top-level ideas
- todo
- true
code_actions_ignore_error
reqlan rq/extension/host/features-commands.rq
A Quick Fix code_actions on a line with diagnostics inserts comment_reference_ignore ( `//rq-ignore-error` ) on the line before the error.
The inserted comment uses the same indent as the error line.
One action is offered per line when that line has one or more diagnostics.
The action is omitted when that line is already suppressed, and when the client asks only for non-quickfix kinds.
Available in `.rq` files and in a comment context in a code file ( references_in_functional_code_comments ).
In `#` comments the action inserts `# //rq-ignore-error` so the line stays a comment.
- implementation
- reqlan-ignore-error-action.ts, reqlan-code-action-provider.ts, code_actions.rs, register-ignore-error-code-actions.ts, ignore-error-comment-filter.ts, main.ts
- status
- done
- tests
- code-actions.test.ts:offers ignore-error quick fix on a line with a linking error, code-actions.test.ts:omits ignore-error when only refactor is requested, code_actions.rs:offers_ignore_error_quick_fix_on_a_line_with_a_linking_error, code_actions.rs:omits_ignore_error_when_only_refactor_is_requested, ignore-error-action.test.ts:inserts indented ignore comment before the error line, ignore-error-action.test.ts:uses tab indent and CRLF when the error line uses them, ignore-error-action.test.ts:wraps the ignore comment for a hash-comment error line, ignore-error-action.test.ts:inserts at the start of the file for a first-line error, ignore-error-action.test.ts:offers one action per diagnostic line, rq-ignore-error already suppresses the line, ignore-error-code-action.test.ts:accepts reqlan source and comment-reference codes, extension-package.test.ts:extension main registers ignore-error code actions for comment files
create_idea_below_idea_containing_unresolved_reference_under_cursor
reqlan rq/extension/host/features-commands.rq
If a local idea reference does not resolve, a Quick Fix code_actions creates a new idea below the idea that contains the reference.
The action uses the unresolved local idea names in the idea that contains the caret:
- one unresolved name: apply `Create '<name>' below` directly
- several unresolved names: offer `Create all unresolved ideas below` and one action per name
Qualified file / import references are omitted. The new idea is an empty block inserted after the containing idea.
- implementation
- reqlan-create-idea-below.ts, reqlan-code-action-provider.ts, code_actions.rs
- status
- done
- tests
- code-actions.test.ts:creates the missing idea below the containing idea when only one is unresolved, code-actions.test.ts:offers all or a specific unresolved idea when the caret idea has several, code-actions.test.ts:omits create-below when the caret idea has no unresolved local references, code-actions.test.ts:omits create-below for a qualified unresolved reference, code-actions.test.ts:omits create-below when only refactor is requested, code_actions.rs:creates_the_missing_idea_below_the_containing_idea, code_actions.rs:offers_all_or_a_specific_unresolved_idea, code_actions.rs:omits_create_below_when_the_caret_idea_has_no_unresolved_local_references, code_actions.rs:omits_create_below_for_a_qualified_unresolved_reference, code_actions.rs:omits_create_below_when_only_refactor_is_requested
installation
reqlan rq/extension/host/installation.rq
reqlan installation has **two sequenced layers** that must not be conflated:
1. extension_installation — host product ( VS Code / Cursor extension ) install and first activation.
2. base_installation — marking a filesystem directory as a reqlan base and seeding its `.reqlan` application memory.
Extension install alone does **not** create a base. Base install alone does **not** open the welcome webview or install host agent skills.
CLI `init` shares the base path with the editor ( init / create_base_onboarding ).
installation_sequencing
reqlan rq/extension/host/installation.rq
End-to-end first-run story ( typical editor user ):
1. User installs the extension from Marketplace / Open VSX / VSIX ( extension_installation ).
2. Host fires an activation_events match ( usually `onStartupFinished` ).
3. activation_sequence synchronously registers contributions and schedules background_startup; onboarding_check may open installation_event ( Welcome to Reqlan webview ) without blocking activation.
4. If no `.reqlan` exists under workspace folders, surfaces offer create-base ( create_base_onboarding ) — user-driven, never auto-created on extension install.
5. base_installation seeds config / ignore / marker; index activate / sync follows ( application_memory ).
6. Optionally, user runs Install Cursor Skills ( workspace_agent_files ) — copies rq-* skills and writes `.cursor/mcp.json`; independent of `.reqlan` seeding.
Ordering constraint: steps 1 – 3 are extension-scoped; steps 4 – 5 are base-scoped; step 6 is workspace agent tooling scoped to the open folder, not the `.reqlan` directory.
extension_installation
reqlan rq/extension/host/installation.rq
Extension-level install covers packing, activation, and first-run host UX — not base filesystem state.
There is **no** VS Code `onInstall` API; install-time behaviour runs on the **first** activation after install ( activation_events ).
Sequencing inside `activate` is owned by activation_sequence:
- Sync register CodeLens / inlay config commands.
- Synchronously register analytical submodule contributions ( commands, activity bar, chat, webviews, AI commands, mutation hooks ) without starting the index ( analytical_submodule_activation ).
- Register import quick-fixes, then schedule index and language-client startup through first_paint_startup / background_startup; sync catalogs once the language client exists.
- Fire-and-forget onboarding_check → welcome_webview_install.
Failures in submodule or language client are logged and must not abort later phases or the welcome check.
Related command surfaces: Show Onboarding ( show_onboarding_command ), Install Cursor Skills ( cursor_skills_install ), Create Base ( create_base_onboarding ).
welcome_webview_install
reqlan rq/extension/host/installation.rq
The **Welcome to Reqlan** onboarding webview is the extension-install UX surface.
Opened once on first activation when `onboardingMessageShown` is false ( installation_event / installation_event_trigger / onboarding_state ).
Content: welcome copy, resolved phonebook links, syntax-highlighted example `.rq`, open-as-untitled control, activity bar / `@reqlan` tips, sponsor thanks.
Must not block activation_sequence; errors are logged only.
Reopen on demand via show_onboarding_command without resetting shown state unless product policy changes.
Implementation: open-thanks-for-installing.ts, onboarding-panel.ts, onboarding.
- status
- done
workspace_agent_files
reqlan rq/extension/host/installation.rq
Agent / AI host files are **workspace** artefacts, not files under `.reqlan/`.
Install Cursor Skills ( cursor_skills_install ) copies bundled `rq-*` skills into `<workspace>/.cursor/skills/` and writes `<workspace>/.cursor/mcp.json` ( install-cursor-skills.ts ): local `packages/mcp/bin/mcp.js` when present, otherwise `npx -y @reqlan/mcp`.
Requires an open workspace folder; does not create a base and does not write into `.reqlan`.
Naming: skills / chat slash commands use `rq-` prefix ( chat_skill_naming ); command palette stays category " reqlan " ( ai_naming ).
AI command surfaces that depend on skills being present: ai_integration, ai_build_requirement, ai_add_to_context, ai_write_plan, ai_fix_stale_references.
Dev sync of the same skill sources into this repo's `.cursor/skills` is a build concern ( build.rq ), distinct from end-user install sequencing.
base_installation
reqlan rq/extension/host/installation.rq
Base-level install marks a directory as a base and seeds shared application memory under `<base>/.reqlan/` ( application_memory ).
Entry points ( same helper create-base.ts ):
- Editor: `reqlan.createBase` / empty-state CTAs ( create_base_onboarding ) — only after discovery finds **zero** bases; never on extension install alone.
- CLI: `reqlan init directory` ( init ).
Idempotent: existing `.reqlan` is left alone ( `created: false` ).
On **new** base creation the sequence is:
1. Create `<base>/.reqlan/` marker directory ( presence = base ).
2. Seed base_config_seed ( `.reqlan/config.json` ).
3. Seed base_rqignore_seed ( `.reqlan/.rqignore` ).
4. Seed base_initialisation_ignore ( `.reqlan/.gitignore` for SQLite artifacts ).
5. Editor rediscovers bases and activates indexing for that base; SQLite `ideas-index.sqlite` appears when the index opens ( not necessarily written at marker creation ).
Child / nested bases follow base_nesting; each base owns its own `.reqlan` seeds and index.
base_config_seed
reqlan rq/extension/host/installation.rq
New bases write `.reqlan/config.json` with `$schema` pointing at the public v1 schema URL via create-base.ts.
Seed shape: `{"$schema":"https://reqlan.com/schemas/v1/config.schema.json"}`.
Semantics and discovery of applying config: configuration_location, configuration_import_roots, base_configuration.
Schema / editor validation: configuration_schema_file.
A child base does not inherit a parent base's config file.
Existing bases are not rewritten ( idempotent create leaves them alone ).
- implementation
- ignore.rs, create-base.ts
- status
- done
- tests
- config.json when creating a new base, config.test.ts:schema file documents importRoots mappings, ignore.rs:create_base_seeds_config_with_public_schema
base_rqignore_seed
reqlan rq/extension/host/installation.rq
New bases write `.reqlan/.rqignore` with gitignore-syntax defaults ( dependencies, venvs, build output, DBs such as `*.db3` and SQLite sidecars, binary globs, commentless_file_ignore, secrets, hidden entries, `.reqlan/` itself ).
Comment text in the seed: rqignore_initialisation.
Built-in defaults always apply even if the file is missing; the seeded file is the editable surface ( configuration_rqignore / rqignore / binary_ignore ).
Used by analytical discovery and indexing walks ( CLI and extension share `@reqlan/analytical` ).
base_vs_extension_boundary
reqlan rq/extension/host/installation.rq
Clear ownership so install steps do not write to the wrong store:
- Extension package / activate / welcome webview → extension_installation ( extension host + `globalState` onboarding key ).
- Activity bar, LSP, chat participant, Ideas Summary → extension runtime after activation_sequence.
- `.reqlan/` marker, `config.json`, `.rqignore`, `.gitignore` ( SQLite artifacts ), ideas index, index diagnostics sqlite → base_installation under `<base>/.reqlan/`.
- Cursor `rq-*` skills + MCP json → workspace_agent_files under `<workspace>/.cursor/`.
Do not store agent skills or MCP config inside `.reqlan`. Do not treat welcome-webview globalState as base-local memory.
installation_event
reqlan rq/extension/host/onboarding/page-thanks-for-installing.rq
On installation of the extension a webview should be opened showing:
- A welcome message
- Resolved links to site, github, docs etc. ( not template placeholders )
- A syntax-highlighted example `.rq` with real URLs ( clickable ) from thanks-for-installing.template.rq after placeholder substitution
- A control to open that example as an untitled `.rq` editor beside the webview
- Short tips for the activity bar and `@reqlan` chat
- A thanks to sponsors
Place in overall install sequencing: welcome_webview_install / extension_installation.
Implemented as a Svelte webview under onboarding bundled to onboarding and opened once on first activation by open-thanks-for-installing.ts via onboarding-panel.ts.
Resource links and template values are resolved at runtime from phonebook through phonebook.ts and posted to the webview; the example block imports thanks-for-installing.template.rq via Vite `?raw` and substitutes `{{…}}` placeholders before display.
Highlighting uses the onboarding tokenizer in rq-highlight.ts.
The source template still uses placeholders such as { { SITE_URL } }; those matching braces are body prose per nested_curly_braces and must parse without errors.
Activation state is stored in extension global state key `onboarding` with `onboardingMessageShown` and `lastVersion` per onboarding-state.ts.
VS Code persists `globalState` in the extension global storage directory ( `globalStorage/reqlan.reqlan-extension/state.vscdb` under the editor user data folder ).
- status
- done
- tests
- parsing.test.ts:parse thanks-for-installing template, onboarding-rq-highlight.test.ts
show_onboarding_command
reqlan rq/extension/host/onboarding/page-thanks-for-installing.rq
A command_palette action should reopen the onboarding webview on demand.
Command: Show Onboarding ( category Reqlan, id `reqlan.showOnboarding` ).
Implemented by register-onboarding-commands.ts calling open_onboarding_page.
Does not reset onboarding_state.
- status
- done
open_onboarding_page
reqlan rq/extension/host/onboarding/page-thanks-for-installing.rq
Opens the onboarding webview panel ( `reqlan.onboarding` ) via open-thanks-for-installing.ts and onboarding-panel.ts.
onboarding_state
reqlan rq/extension/host/onboarding/page-thanks-for-installing.rq
Onboarding persistence uses VS Code `ExtensionContext.globalState` under key `onboarding` in onboarding-state.ts.
Fields: `onboardingMessageShown`, `lastVersion`.
installation_event_trigger
reqlan rq/extension/host/onboarding/page-thanks-for-installing.rq
The installation event should be checked and triggered at extension activation.
Verified: main.ts schedules `openThanksForInstallingIfNeeded` after the activity-bar paint gate or 400 ms ( not in the same tick as sidebar claim ), and onboarding_check documents the gating behaviour.
- status
- done
scope
reqlan rq/extension/host/scope.rq
these requirements describe the vscode extension and lsp for reqlan
lsp_support
reqlan rq/extension/host/scope.rq
the extension should provide an lsp server for. rq files, enabling navigation, validation, and computed views across the requirement graph
vscode_extension
reqlan rq/extension/host/scope.rq
the extension should integrate with vscode as the primary developer-user environment
extension_startup_reliability
reqlan rq/extension/host/startup-performance.rq
Reqlan startup must make the activity-bar shell and contributed commands available before optional indexing, parser construction, database initialization, or language-client startup can monopolize the extension host.
The implementation contract is first_paint_contract, webview_claim_race, deferred_startup_sequence, lazy_runtime_dependencies, and development_bundle_freshness.
Operational diagnosis follows startup_diagnostics.
activation_sequence loading_state nonblocking_index extension_bundle
- status
- done
- tests
- "../../../packages/extension/test/startup-gate.test.ts", "../../../packages/extension/test/safe-webview-post.test.ts", "../../../packages/analytical/src/index-store/workspace-index.ts"
observed_failure
reqlan rq/extension/host/startup-performance.rq
Failure signature:
- Reqlan contributes its activity-bar container and header buttons from `package.json`, but the Context view remains on VS Code's built-in spinner before the extension-owned " Loading Reqlan … " shell.
- Contributed commands may be visible as menu items yet fail with `command 'reqlan.*' not found`.
- The extension-host CPU profile can be mostly idle after the failure.
This combination means static manifest contributions loaded but the extension module failed before `activate()` registered command handlers and the webview provider.
invalid_url_activation_failure
reqlan rq/extension/host/startup-performance.rq
The concrete incident failed while requiring `out/extension/main.cjs`, before `activate()` ran:
`TypeError: Invalid URL` in `embedPhysicsCoreSource`.
Runtime `readFileSync(new URL(..., import.meta.url))` is unsafe when esbuild emits CommonJS for an ES2017 target: `import.meta.url` is unavailable / empty and source-relative assets do not exist beside the bundled entry.
The HTML export used to embed physics via `html-export-assets.ts` `embedPhysicsCoreSource`. That writer is gone; export now inlines assets from app.js.
Code that still needs a module directory or `createRequire` ( core engine loader and parse worker ) must not mention `import.meta` statically in a way that esbuild CJS empties: prefer CJS `__dirname` / `__filename` when those exist ( extension host bundle ), and `import.meta.url` on the Node ESM path ( CLI / MCP ).
The host esbuild step defines `import.meta.url` as `import_meta_url` from this file's `__filename` so the CJS bundle stays valid and does not warn `empty-import-meta`. CLI / MCP keep the TypeScript `import.meta.url` emit.
Do not eval `import.meta.url` — Node 24 treats that as a script eval and throws `Cannot use 'import.meta' outside a module`.
load-native.ts
reqlan-async-parser.ts
esbuild.mjs
- status
- done
- tests
- "../../../packages/analytical/test/load-native.test.ts", "../../../packages/extension/test/extension-package.test.ts"
extension_host_process_model
reqlan rq/extension/host/startup-performance.rq
One Node extension-host process for the development window is normal; multiple workers are not required for a healthy Reqlan activation.
The language server is a separate child process launched only after extension activation reaches `LanguageClient.start()`.
Therefore an idle extension host with no Reqlan language-server child is consistent with an earlier module-load / activation failure, not evidence that a worker is missing.
first_paint_contract
reqlan rq/extension/host/startup-performance.rq
The platform spinner ends only after VS Code loads the host module, calls `activate`, the provider registers, and `resolveWebviewView` assigns HTML.
`resolveWebviewView` is async: it binds the view, yields one turn so the overlay can be claimed, then assigns the lightweight HTML / Svelte shell ( retry once on invalid-state ). It does **not** `postMessage` in that method.
The webview installs its host message listener, mounts, waits for its first animation frame, then posts the one-shot `ready` signal from a queued task.
Host messages start only after that handshake. Index discovery / sync waits for the same signal so synchronous parser or database setup cannot race the first visible frame.
Windows overlay restore can dispose and re-resolve the sidebar; the provider rebinds and waits for a new `ready`.
first_paint_startup webview_claim_race
App.svelte
app.svelte.ts
startup-gate.ts
safe-webview-post.ts
- status
- done
- tests
- "../../../packages/extension/test/startup-gate.test.ts", "../../../packages/extension/test/safe-webview-post.test.ts"
webview_claim_race
reqlan rq/extension/host/startup-performance.rq
Setting `webview.html` or calling `postMessage` before the workbench has claimed the overlay ( or after it has disposed it ) can fail with `Webview is in an invalid state` / `Webview is disposed`.
This is intermittent and more common on Windows during extension init, when the activity-bar view is restored in the same tick as another webview ( first-run onboarding ).
Contract:
- Activity-bar host posts only after the webview's `ready` signal; `post` is a no-op until then and swallows disposed / invalid-state errors.
- `resolveWebviewView` may run more than once: dispose prior view listeners, clear `webviewReady`, rebind, reassign HTML.
- First-run onboarding waits for the activity-bar paint gate or 400 ms, whichever first, so it does not register a second webview service worker during sidebar claim. Palette `reqlan.showOnboarding` stays immediate.
Index and language-client startup still use the existing paint / timeout fallbacks — a dead sidebar must not strand indexing.
first_paint_contract onboarding_check
activity-bar-webview-provider.ts
main.ts
safe-webview-post.ts
- status
- done
- tests
- "../../../packages/extension/test/safe-webview-post.test.ts"
deferred_startup_sequence
reqlan rq/extension/host/startup-performance.rq
Required order:
1. Load the smallest practical host entry.
2. Synchronously register commands and the activity-bar provider; return from `activate`.
3. Yield one turn, assign the activity-bar shell, and wait for the post-first-frame `ready` handshake. Do not `postMessage` until `ready`.
4. Start index discovery / sync after `ready`; if the sidebar stays closed, start after a bounded three-second fallback so startup indexing and watchers are not lost.
5. Start the language client after `ready`, with a one-second fallback so language features work when the sidebar stays closed.
6. Open first-run onboarding after the same paint signal or 400 ms, so it does not race the sidebar iframe ( webview_claim_race ).
7. Report incremental index progress inside the already-painted sidebar.
The ready signal and both startup paths are one-shot / idempotent.
background_startup
- status
- done
lazy_runtime_dependencies
reqlan rq/extension/host/startup-performance.rq
Base discovery must be cheap:
- Constructing `WorkspaceIndex` does not construct Langium / Chevrotain services; index sync uses the core native engine ( rusqlite ).
- The host-matching `reqlan_napi` `.node` is required at activate; there is no sql. js vendor bundle in the extension host.
- Export / physics source is generated at build time rather than read via extension-runtime URLs.
workspace-index.ts
sqlite-store.ts
index-diagnostics-store.ts
esbuild.mjs
- status
- done
- tests
- "../../../packages/analytical/src/index-store/workspace-index.ts"
development_bundle_freshness
reqlan rq/extension/host/startup-performance.rq
F5 executes `package.json.main` ( `out/extension/main.cjs` ), not TypeScript source.
`out/`, generated webview media, and copied syntaxes are gitignored, so launching without a build can run missing or stale artifacts even when source already contains the fix.
`.vscode/launch.json` therefore uses a deterministic pre-launch task that invokes the extension build orchestrator directly; root `pnpm run build:ext` delegates to the same script.
The task content-fingerprints Langium and physics generation, each webview, packaging media, and extension-host / language-server output; `tsc -b` retains project-reference incrementality. Unchanged artifacts are verified and skipped before the development host opens.
Watch mode remains useful during iteration, but concurrent watchers do not restart an already-running extension host or language-server child; stop and start F5 after host / server changes.
launch.json
tasks.json
- status
- done
startup_diagnostics
reqlan rq/extension/host/startup-performance.rq
Diagnosis order:
1. Read the development extension host's `remoteexthost.log`; find `ExtensionService#_doActivateExtension reqlan.reqlan-extension`.
2. Distinguish code-loading time, activate-call time, and activate-resolved time.
3. If activation failed, use the first Reqlan stack frame rather than inferring a CPU hang.
4. If manifest UI exists but every command is missing, investigate module load / activation before indexing or webview data.
5. If the extension-owned " Loading Reqlan … " shell appears, provider resolution succeeded; subsequent delays belong to webview bootstrap or index readiness.
6. Confirm `out/extension/main.cjs` is newer than changed source and includes a lazy vendor sql-asm import.
CPU-idle profiles do not disprove activation failure: once `require()` throws, the host can remain healthy and mostly idle while Reqlan stays unregistered.
activation_events_learning
reqlan rq/extension/host/startup-performance.rq
Modern VS Code derives activation for contributed views and commands.
The incident log explicitly showed activation event `onView:reqlan.activityBar`, so the missing-command failure was not caused by a missing explicit `onView` entry.
Activation-event changes should be justified from host logs and target-version behavior, not used to mask a module-load exception.
verification_contract
reqlan rq/extension/host/startup-performance.rq
Startup changes are complete only when:
- The production extension build succeeds and emits `out/extension/main.cjs`.
- The main bundle does not embed a sql. js vendor; index open requires the core native engine.
- Extension startup-gate, webview-claim, and analytical lazy-service tests pass.
- Activity-bar shell paint is visually checked in a newly restarted F5 development host; activation failures are cached for the lifetime of a failed host session.
- Requirement analysis resolves the updated startup graph.
- status
- done
- tests
- "../../../packages/extension/test/startup-gate.test.ts", "../../../packages/extension/test/safe-webview-post.test.ts", "../../../packages/analytical/src/index-store/workspace-index.ts"
git_idea_timeline_analysis
reqlan rq/extension/index-host/git-codelens.rq
Idea creation and last-modified dates, plus change count, are derived from git history by the
`git_dates` analyser and stored on the ideas index
( `git_created_at` / `git_modified_at` / `git_change_count` ).
Calculation is owned by git_dates_background_indexing / git_dates — not by
on-the-fly editor, Activity Bar focus, Timeline open, or Ideas table load.
Active-editor queue priority for fill-in is specified on git_idea_timeline_analysis.
Implemented by git_dates.rs and
sqlite-store.ts.
git_dates_background_indexing
git_dates_rate_cap
git_dates
ideas_list
- status
- done
- tests
- idea-timeline.test.ts, idea-timeline.test.ts:upsert preserves analyser git dates and change count across reindex, idea-timeline.test.ts:listIdeaIdsMissingGitDates returns ideas without dates, idea-timeline.test.ts:listIdeaIdsMissingGitDates includes ideas missing change count, idea-timeline.test.ts:listIdeaIdsMissingGitDates can filter or prefer a file, git-dates-background.test.ts:processes active-file priority ids before the global backlog, ideas-git-columns-perf.test.ts
git_dates_background_indexing
reqlan rq/extension/index-host/git-codelens.rq
Host wiring for git_idea_timeline_analysis / git_dates: after the ideas index is
ready ( and when the catalog updates ), missing idea git dates must be filled by a mostly silent
background process:
- small batches
- yields between batches so the extension host stays interactive
- no progress UI / no blocking of Activity Bar context load or Timeline tab open
- session-scoped attempted set so failed lookups are not hammered repeatedly
- queue priority: ideas in the active `.rq` editor file are attempted before the global backlog;
switching the active editor re-prioritises ( in-flight wave may stop and reschedule )
- catalog / save scheduling follows git_dates_rate_cap
- git / node helper processes stay hidden per consumption_silence
Consumers only read indexed columns; they must not invoke `git_dates` on the UI path.
git_dates_background_indexing
git_dates_background_indexing
git_dates_background_indexing
timeline_page
- implementation
- git-dates-background.ts, register-git-dates-background.ts, sqlite-store.ts, git_dates.rs
- status
- done
- tests
- git-dates-background.test.ts, git-dates-background.test.ts:processes missing ids in small batches and yields between them, git-dates-background.test.ts:does nothing when the index is not ready, git-dates-background.test.ts:marks ids attempted even when the analyser fails, git-dates-background.test.ts:processes active-file priority ids before the global backlog, git-dates-background.test.ts:stops early when shouldStop flips so a new file can be prioritised, git-dates-background.test.ts:catalog events debounce and do not follow the short editor delay, idea-timeline.test.ts:listIdeaIdsMissingGitDates returns ideas without dates, idea-timeline.test.ts:listIdeaIdsMissingGitDates can filter or prefer a file
git_dates_rate_cap
reqlan rq/extension/index-host/git-codelens.rq
Git history analysis is expensive ( `git log -L` and follow logs per idea ).
Do not start a git_dates wave on every `.rq` save or catalog notify.
Catalog and index-status events must debounce ( quiet period after the last notify )
and must wait a minimum gap after a wave that actually filled dates.
Editor-switch priority and draining a capped wave may use the short idle delay.
Distinct from indexing_trigger_filesave: the ideas
index still updates on save; only git analysis is rate-capped.
Related: git_dates_background_indexing, git_dates,
idea_index_triggers, git_information_capture,
consumption_silence.
- implementation
- git-dates-background.ts, register-git-dates-background.ts
- status
- done
- tests
- git-dates-background.test.ts:catalog events debounce and do not follow the short editor delay, git-dates-background.test.ts:catalog waves wait for the min gap after a fill
git_based_history
reqlan rq/extension/index-host/git-codelens.rq
there should be a code lens button for viewing an idea history through git.
Should accept close matches and likeley file moves
should consume the same state as the context_scope
Dates come from indexed git_idea_timeline_analysis state filled by git_dates_background_indexing.
- idea
- true
- todo
- CodeLens button to open idea git history
git_date_inlayhints
reqlan rq/extension/index-host/git-codelens.rq
Should show references and date created per git_based_history.
Creation dates must come from already-indexed git dates via git_dates_background_indexing,
not a synchronous git walk on inlay render.
- todo
- true
indexing_trigger_filesave
reqlan rq/extension/index-host/graph-analysers.rq
indexing should be triggered by. rq file create / change / delete via watchers, and by allowlisted source files that may contain comment references.
indexing_trigger_manual
reqlan rq/extension/index-host/graph-analysers.rq
Indexing should be triggered by manual indexing commands ( Refresh / Clear & rebuild ).
Refresh and Clear & rebuild always rediscover bases first via
refresh_rediscovers_bases /
base-registry.ts `refresh`, then soft-sync or
rebuild the active base.
- implementation
- base-registry.ts, index-service.ts, register-commands.ts
- tests
- base-registry-refresh.test.ts:refresh rediscovers a base created after an empty discovery, base-registry-refresh.test.ts:refresh rediscovers a nested base added after first discovery
indexing_trigger_open
reqlan rq/extension/index-host/graph-analysers.rq
After the activity bar's first painted frame / base activate, run one soft sync ( mtime-skipped ) so the index is warm without delaying the sidebar shell.
This is a startup pass — not the idle checker ( indexing_trigger_auto ).
indexing_trigger_auto
reqlan rq/extension/index-host/graph-analysers.rq
When the editor host is idle, run a **background staleness check** — not a reindex and not a soft full sync UI pass.
Philosophy: computationally cheap. Load document mtimes in **one** SQLite read, compare each file's FS mtime in memory, and only then index mismatched or new files; drop deleted docs in one batched delete.
A single MAX ( mtime ) watermark is not sufficient ( one file can get newer while another gets older ).
If nothing is stale: no state transition, no progress UI, no parse.
If some files are stale: index **only those files** under nonblocking_index.
Schedule after a quiet period with no index activity; prefer running when the window is unfocused; defer or cancel if the user becomes active again.
Extension host only ( index-service.ts ); CLI / MCP have no idle loop ( they sync on activate / command ).
- status
- done
list_all_ideas
reqlan rq/extension/index-host/graph-analysers.rq
The extension should provide a command to list all ideas in the workspace with file location and summary.
file_related_requirements
reqlan rq/extension/index-host/graph-analysers.rq
The extension should provide a view or command to get requirements relating to the currently open file.
File-related lookup should follow both explicit file references and comment rq: links in that file.
Comment links are read from indexed `comment_link` edges ( index_code_files ), not only the open buffer.
click_code_file uses the same indexed backlinks and comment links when the click target is a code file.
host_index_capabilities
reqlan rq/extension/index-host/graph-analysers.rq
Host-facing analysers and commands over the shared index:
list_all_ideas, file_related_requirements,
index_ideas, index_technology, local_graph_analysis,
semantic_analysis, git_dates, completion_tracking,
deprecation_impact_analysis.
Application memory: application_memory.
index_diagnostics
reqlan rq/extension/index-host/index-diagnostics.rq
Indexing performance diagnostics: measure and inspect time spent indexing a index base.
Timing is persisted in a dedicated **diagnostic index** under application memory ( index_diagnostics_store ), not in `ideas-index.sqlite`, so history survives Clear & rebuild.
Surfaces: index_diagnostics_webview. Owned by `@reqlan/analytical` for recording; the extension hosts the webview.
- status
- done
index_diagnostics_metrics
reqlan rq/extension/index-host/index-diagnostics.rq
For each sync / index run on a base, record:
- wall-clock **sum / total duration** of the pass
- **file count** ( visited ), skipped-by-mtime count, indexed ( parse / persist attempted ) count, error count
- **average path depth** of visited files ( segments under the base root )
- per-file **duration** and outcome ( `mtime_skip` | `mtime_refresh` | `hash_skip` | `persisted` | `error` )
Runs are attributable to a trigger ( `soft_sync` | `rebuild` | `enqueue` | `stale` ).
Instrumentation wraps workspace-index.ts soft sync and nonblocking_index single-file paths via index-diagnostics-store.ts.
- implementation
- index-diagnostics-store.ts, workspace-index-file.ts, workspace-index-sync.ts, workspace-index.ts
- status
- done
index_diagnostics_webview
reqlan rq/extension/index-host/index-diagnostics.rq
An editor webview panel displays index timing diagnostics for the active base.
Capabilities:
- Base / latest-run summary: total time, file counts, average depth
- Drill into recent runs
- Rank files by duration ( slowest first ); show outcome and path depth
Opened by command `reqlan.openIndexDiagnostics` ( open_index_diagnostics ).
Optional entry from workspace index health ( workspace_pane ) may link later; command is the primary entry.
Implementation: index-diagnostics-panel.ts, App.svelte.
- implementation
- index-diagnostics-panel.ts, register-index-diagnostics.ts, index-diagnostics
- status
- done
open_index_diagnostics
reqlan rq/extension/index-host/index-diagnostics.rq
Command palette action **Open Index Diagnostics** ( `reqlan.openIndexDiagnostics` ) opens index_diagnostics_webview for the active base.
Shows total index time, run drill-down, and per-file ranking ( duration, depth, outcome ).
- status
- done
application_memory
reqlan rq/extension/index-host/index.rq
Base-local application memory for reqlan tools lives under `<base>/.reqlan/`.
The presence of `.reqlan` **marks** a directory as a base; each base owns its own store.
Shared by the VS Code extension, cli_package, and MCP ( server.ts ) — not VS Code `globalStorageUri` / extension-private storage.
The ideas graph index ( index_ideas and index_technology ) persists as `ideas-index.sqlite` inside that directory.
Schema: ideas_index_sqlite.
Index timing diagnostics persist separately as `index-diagnostics.sqlite` ( index_diagnostics_store / index_diagnostics ) so rebuilds of the ideas index do not wipe history.
Click session state persists as `click-sessions.sqlite` ( click_session ) so agent / CLI click cursors survive ideas-index rebuilds.
Diagnostics schema: diagnostics_sqlite.
WAL sidecars and JSON siblings: reqlan_directory_layout.
Export form defaults ( all formats via export.rq".export_webview, including HTML options in html-export.rq".html_export_form ) persist as `export_settings.json` in the same directory ( active base ).
Path ignore rules live as `.rqignore` in the same directory ( rqignore / configuration_rqignore ).
Git ignore for SQLite stores lives as `.gitignore` in the same directory ( base_initialisation_ignore ).
Path resolution is owned by application-memory.ts ( `resolveApplicationMemoryPath` ); consumers must use it ( or `REQLAN_INDEX_PATH` override for a single store ) so tools read and write the same store for a given base.
Multi-base discovery / registry: multi_base_environment. Index engine ownership: ownership. Extension wiring: index.ts.
Aligns with function_parity: shared analytical memory, not host-only state.
- status
- done
index_diagnostics_store
reqlan rq/extension/index-host/index.rq
Per-base diagnostic timing index at `<base>/.reqlan/index-diagnostics.sqlite`.
Sibling of `ideas-index.sqlite`; not deleted by Clear & rebuild.
Records sync runs and per-file durations for index_diagnostics_metrics.
Webview: index_diagnostics_webview.
- implementation
- index-diagnostics-store.ts, application-memory.ts
- status
- done
rqignore
reqlan rq/extension/index-host/index.rq
`.reqlan/.rqignore` filters which paths discovery and indexing crawl, using gitignore syntax relative to the base root.
Owned by rqignore.ts in `@reqlan/analytical` so CLI and editor share behaviour.
Defaults cover `node_modules/`, virtualenvs, build dirs ( `bin/`, `generated/`, `out/` ), VCS / editor stores, database files ( `*.db3`, sqlite ) and SQLite sidecars, binary globs ( binary_ignore ), `*.html`, secrets, and hidden entries.
Walks also skip common files that have no comments ( commentless_file_ignore ).
New bases seed the file via rqignore_initialisation.
Product configuration statement: configuration_rqignore.
- implementation
- rqignore.ts, application-memory.ts, rqignore.ts, ignore.rs, create-base.ts, base-discovery.ts, workspace-index.ts
- status
- done
- tests
- rqignore.test.ts, rqignore.test.ts:seeded rqignore comments explain all features, .rqignore when creating a new base, workspace-index.test.ts:skips .rq files under rqignore patterns, sync.rs:default_rqignore_skips_node_modules
rqignore_initialisation
reqlan rq/extension/index-host/index.rq
New bases seed `.reqlan/.rqignore` with comments that explain every feature of rqignore, binary_ignore, and commentless_file_ignore.
Written when a base is created: base_rqignore_seed / base_initialisation.
Comments cover purpose ( discovery and index walks ), base-root relative paths, gitignore syntax, last matching rule, `!` negation, built-in defaults that always apply, binary opt-in, hidden paths, `*.secret.rq`, SQLite sidecars, files that have no comments ( rqignore_initialisation ), and `.reqlan/` itself.
The seeded file is the editable surface. Built-in rules still apply if a user deletes a line.
Existing `.rqignore` files are not rewritten ( base_installation is idempotent ).
- implementation
- rqignore.ts, rqignore.ts, ignore.rs, create-base.ts
- status
- done
- tests
- rqignore.test.ts:defaultRqIgnoreFileContents documents gitignore-style defaults, rqignore.test.ts:seeded rqignore comments explain all features, ignore.rs:seeded_rqignore_explains_features, .rqignore when creating a new base
binary_ignore
reqlan rq/extension/index-host/index.rq
Discovery, coverage, and index walks skip binary files by default.
Built-in rqignore patterns include a broad set of binary globs ( images, archives, packages, native objects, fonts, media, and office files ).
Opt in with a gitignore negation in `.reqlan/.rqignore`. Example: `!*.bin` includes files with a `.bin` extension.
Opted-in files can receive index_code_files comment indexing. They are not parsed as `.rq` sources.
The editor source watcher stays on allowlisted text extensions. A soft sync indexes opted-in binary paths from the scan list. Idle stats stored paths and does not walk.
Same filter as configuration_rqignore.
- implementation
- rqignore.ts, rqignore.ts, ignore.rs, sync.rs
- status
- done
- tests
- rqignore.test.ts:defaults ignore node_modules, venv, db3, and binary paths, rqignore.test.ts:inverse rqignore patterns opt binary files back in, ignore.rs:default_rqignore_skips_binary_files_until_negated, code_file_index.rs:skips_binary_comment_files_unless_rqignore_negation, sync.rs:default_rqignore_skips_node_modules
text_prefix_skip
reqlan rq/extension/index-host/index.rq
Before any index content read, inspect at most the first 8 KiB.
Skip the file when that prefix has a NUL, a UTF-16 BOM ( `FF FE` or `FE FF` ), or invalid UTF-8.
A trailing incomplete UTF-8 code unit is not a skip: the rest of the file may finish the character.
Skip when the file is larger than 1 MiB.
A rejected prefix is not followed by a read of the remainder.
`.rq` files and allowlisted code files use the same check.
This is in addition to binary_ignore extension globs.
- status
- done
- tests
- text.rs:nul_rejects, text.rs:utf16_bom_rejects, text.rs:invalid_utf8_rejects, text.rs:trailing_incomplete_utf8_is_not_a_reject, scan.rs:prefix_skip_does_not_index_non_text
commentless_file_ignore
reqlan rq/extension/index-host/index.rq
Discovery, coverage, and index walks skip common files that have no comment syntax.
The set includes JSON ( `.json`, `.jsonl`, `.ndjson` ), tabular data ( `.csv`, `.tsv` ), lockfiles, checksums, minified scripts, source maps, notebooks, and certificates.
These files cannot hold `rq:` comment references.
SQLite WAL, SHM, and journal sidecars stay with the database patterns in rqignore ( `*.sqlite-wal`, `*.sqlite-shm`, `*.sqlite-journal`, and the same suffixes on `.sqlite3`, `.db`, and `.db3` ).
Opt in with a gitignore negation in `.reqlan/.rqignore`. Example: `!*.json`.
JSON with comments ( `.jsonc`, `.json5` ) stays eligible for index_code_files.
The seeded file lists the same patterns ( rqignore_initialisation ).
- implementation
- rqignore.ts, rqignore.ts, ignore.rs
- status
- done
- tests
- rqignore.test.ts:defaults ignore json, sqlite sidecars, and files without comments, rqignore.test.ts:inverse rqignore patterns opt json back in, ignore.rs:default_rqignore_skips_files_without_comments_until_negated, ignore.rs:seeded_rqignore_explains_features
idea_index_triggers
reqlan rq/extension/index-host/index.rq
Refresh automatically on `.rq` file change via watchers ( indexing_trigger_filesave ).
Idle: cheap background staleness check — indexing_trigger_auto.
Git-dates fill is not an index trigger; it is a later analyser with
git_dates_rate_cap.
git_information_capture
reqlan rq/extension/index-host/index.rq
Capture and surface git development history for requirements and files — not only working-tree staging status.
On-demand / index-accessible:
- ownership and top authors ( name; email when available )
- creator ( first introduction ) and last meaningful modification
- edit frequency / commit count for the focus path or idea line range
- recent commit trail ( subject, author, authoredAt, short hash ) for the git_context lens
Idea dates and change counts come from git_dates /
git_dates_background_indexing, not from a git walk on every save
( git_dates_rate_cap ).
Activity Bar git CLI calls stay hidden on Windows ( consumption_silence ).
Future: adjacency score from edit state and frequency of neighbours.
Feeds development_history_signals and git_history_lens.
sqlite_artifact_lifecycle
reqlan rq/extension/index-host/sqlite-artifact-lifecycle.rq
Base SQLite artifacts under `<base>/.reqlan/` ( base_ownership ) must not stay locked for the
whole extension session. The host opens them only while work runs, then releases file handles
so users can delete or replace the files.
Aligns with event_driven: open and close are reactions to index or analysis events, not a
permanent connection or a reconnect loop.
Mediation: only workspace-index.ts / open-analysis-api.ts own SQLite connections. The extension
adapter ( index-service.ts ) must not keep a second long-lived analysis runtime beside the
index, and must not call native open without a matching dispose / release.
Related: index_sequencing, idle_stale_check, headless_consumers, multi_base_environment.
- implementation
- index-service.ts, base-registry.ts, workspace-index.ts, open-analysis-api.ts, native-analysis-api.ts
- status
- done
- tests
- sqlite-artifact-release.test.ts:dispose releases ideas-index so the file can be unlinked, sqlite-artifact-release.test.ts:WorkspaceIndex deactivate releases sqlite artifacts, sqlite-artifact-release.test.ts:BaseRegistry releaseArtifacts closes handles but keeps descriptors, open-analysis-api.test.ts:opens the native engine when the host .node is available
release_when_idle
reqlan rq/extension/index-host/sqlite-artifact-lifecycle.rq
After an index or analysis pass finishes, and after the idle quiet period
( idle_stale_check / indexing_trigger_auto ), index-service.ts must release every open
base SQLite handle via base-registry.ts `releaseArtifacts` → workspace-index.ts `deactivate`.
Descriptors stay registered so the next event can reopen the same base.
Idle must not leave connections open after a heal / sync, and must not schedule another open
unless a real host event arrives ( file change, pin / switch, focus reopen, command, UI query ).
- implementation
- index-service.ts, base-registry.ts, workspace-index.ts
- status
- done
- tests
- sqlite-artifact-release.test.ts:BaseRegistry releaseArtifacts closes handles but keeps descriptors, base-registry-catchup.test.ts:deactivate returns to uninitialized so a base can be reopened
analysis_api_dispose
reqlan rq/extension/index-host/sqlite-artifact-lifecycle.rq
open-analysis-api.ts `openAnalysisApi` dispose must close the native analysis runtime and drop
its SQLite connection ( ideas index and click-sessions ). A no-op dispose is a defect.
Extension commands use a short-lived `withAnalysisApi` ( open → run → dispose ) mediated by
open-analysis-api.ts; they must not cache `NativeAnalysisApi` for the session.
- implementation
- open-analysis-api.ts, native-analysis-api.ts, index-service.ts
- status
- done
- tests
- sqlite-artifact-release.test.ts:dispose releases ideas-index so the file can be unlinked, runtime-engine.test.ts:CLI runtime opens AnalysisApi through the core engine
event_driven_base_access
reqlan rq/extension/index-host/sqlite-artifact-lifecycle.rq
Extension interaction with bases is event-driven and goes through the analytical package:
- Discover / pin / focus / file watch / command / UI query → open or `ensureBaseReady`
- Sync, stale check, or analysis work runs
- Quiet idle → release_when_idle
No always-on connection and no continuous reconnect loop.
Headless CLI / MCP already open per command via open-analysis-api.ts ( headless_sync_on_ready ).
- implementation
- index-service.ts, base-registry.ts, open-analysis-api.ts
- status
- done
- tests
- sqlite-artifact-release.test.ts:BaseRegistry releaseArtifacts closes handles but keeps descriptors, base-registry-catchup.test.ts:ensureBaseReady opens and soft-syncs an uninitialized base
references_in_functional_code_comments
reqlan rq/extension/language/comment-references/functional-code-comment-references.rq
Comments in functional code should be able to reference reqlan ideas using the an `rq:` prefixed to an idea: `rq:idea` as demonstrated in python, but actually applicable to any language's comment context:
Editor hosts are every language except comment_reference_language_blocklist.
With the rust language server, a resolved `rq:…` site is Ctrl + click navigable via go-to-definition.
File document links stay out of the editor ( editor_reference_activation ).
Comment `rq:…` sites use TextMate `meta.link.reqlan markup.underline` so the resting editor shows they are link-shaped ( comment_reference_resting_underline ).
After that goto, Alt + Left restores the comment-host caret ( comment_reference_navigate_back ).
Missing ideas keep the error underline and have no definition target.
Relates to comment_reference_refactor_support, comment_reference_import_root_alias,
language_server_rust,
editor_reference_activation.
- demos
- features-code-comment.text.js, features-code-comment.text.py
- implementation
- session.rs, main.ts, register-comment-reference-links.ts, reqlan-comment.injection.json
- status
- done
- tests
- linking.test.ts:comment references in source files resolve to rq ideas, references.test.ts:finds rq: references in feature demo source files, references.test.ts:finds rq: comment references in python triple-quoted comments, session.rs:comment_links_share_one_resolution, session.rs:comment_definition_follows_a_resolved_rq_reference, editor-link-activation.test.ts:comment injection link scope includes markup.underline, editor-link-activation.test.ts:package.json contributes comment.rq.injection
comment_reference_resting_underline
reqlan rq/extension/language/comment-references/functional-code-comment-references.rq
In non- `.rq` source comments, every `rq:…` token must show a resting underline so it is clear the site is link-shaped.
Use TextMate scope `meta.link.reqlan markup.underline` via the comment injection grammar.
Do not rely on file document links for that cue — those stay stripped ( editor_reference_activation ).
Navigation remains Ctrl + click go-to-definition for resolved sites ( references_in_functional_code_comments ).
Related: comment_reference_resting_underline, comment_support.
- implementation
- reqlan-comment.injection.json, package.json
- status
- done
- tests
- editor-link-activation.test.ts:comment injection link scope includes markup.underline, editor-link-activation.test.ts:package.json contributes comment.rq.injection
comment_reference_navigate_back
reqlan rq/extension/language/comment-references/functional-code-comment-references.rq
A go-to-definition JUMP from a comment `rq:…` host must push the pre-jump caret onto the same navigate-back stack as `.rq` jumps.
The stack tracks every non-blocklisted language ( comment-reference-languages.ts ) as well as `.rq`.
Only landings in `.rq` / `reqlan` are recorded, so other language servers do not fill the stack.
Alt + Left ( `reqlan.navigateBack` ) restores that caret when `reqlan.canNavigateBack` is set, in any focused editor.
Related: references_in_functional_code_comments, comment_reference_language_blocklist, editor_reference_activation.
comment_reference_language_blocklist
reqlan rq/extension/language/comment-references/functional-code-comment-references.rq
Comment rq editor features ( goto, diagnostics, ignore actions, navigate-back origin tracking ) apply to every language except a small blocklist.
The blocklist is `reqlan` plus non-source editor buffers ( log, search-result, SCM input, git commit / rebase, github-issues ).
The rust language client uses a file-scheme document selector and skips sync for blocklisted languages.
TextMate resting underline injects into a wide `injectTo` scope list ( best-effort; goto still works without a matching grammar scope ).
Related: references_in_functional_code_comments, comment_reference_resting_underline, comment_reference.
- implementation
- comment-reference-languages.ts, main.ts, register-definition-navigation.ts, register-comment-reference-links.ts, register-ignore-error-code-actions.ts, package.json
- status
- done
- tests
- definition-navigation.test.ts:tracks non-blocklisted languages for navigate-back, editor-link-activation.test.ts:package.json contributes comment.rq.injection, comment-reference-languages.test.ts:blocklist excludes reqlan and editor chrome
comment_reference_resolution_error_state
reqlan rq/extension/language/comment-references/functional-code-comment-references.rq
comment_reference_resolution_error
The language server must share one resolution result for clickable links and the error underline.
Resolve comment references once against the loaded idea index, then reuse that result for both consumers.
When you create an idea that matches a comment reference, the language server must clear the underline and the missing-idea message.
Resolution and the index should be performed once and shared between consumers.
- implementation
- reqlan-comment-diagnostics.ts, reqlan-neighbor-parse.ts, reqlan-document-builder.ts, reqlan-document-link-provider.ts, reqlan-validator.ts, register-comment-reference-links.ts, session.rs, comment.rs
- status
- done
- tests
- comment-reference-resolution.test.ts:shares one presentation so a matching idea clears the underline and adds a link, comment-reference-resolution.test.ts:publishes a missing-idea diagnostic and no document link until the idea exists, comment-reference-resolution.test.ts:clears the underline and creates a link after a matching idea is added, comment-reference-resolution.test.ts:relinks comment references only when the target file changes, comment-reference-resolution.test.ts:revalidates comment-reference underlines when a matching idea is created on disk, outbound-hop.test.ts:comment references confirm the neighbor idea without loading Langium, session.rs:comment_links_share_one_resolution, session.rs:comment_definition_follows_a_resolved_rq_reference
comment_reference_import_root_alias
reqlan rq/extension/language/comment-references/functional-code-comment-references.rq
Qualified comment references use the same path forms as imports, including import-root aliases such as `@/`.
`rq:idea` resolves against the alias's import-root directory ( workspace folder by default ), not the source file directory.
`@reqs` without a following `/` is not an alias. Configured aliases and roots follow configuration_import_root_alias and configuration_import_roots.
The language server applies this when resolving comment references in `.rq` files. The extension applies the same core resolver for `rq:…` links in non- `.rq` source.
Related: comment_reference, references_in_functional_code_comments, import_paths.
- implementation
- reqlan-path-resolve.ts, reqlan-comment-diagnostics.ts, reqlan-comment-resolver.ts, comment-reference-path-context.ts, register-comment-reference-links.ts, comment.rs, path.rs
- status
- done
- tests
- comment-reference-resolution.test.ts:creates a document link for an import-root aliased comment reference, as a path relative to the source file, comment-reference-resolution.test.ts:resolves a configured alias in a comment reference, comment-reference-resolution.test.ts:accepts an import-root aliased comment reference in a loaded document, path-resolve.test.ts:resolveAuthoredFsPath joins aliased remainder to the workspace folder, path-resolve.test.ts:pathResolveContextFromWorkspaceFolders picks the longest matching folder, against the workspace folder for extension comment links, comment.rs:resolves_aliased_qualified_comment_path, session.rs:comment_links_share_one_resolution
remote_imports
reqlan rq/extension/language/support/features-imports.rq
Reqlan files should support importing requirements from remote urls.
Remote import syntax should follow import " https://company.com/reqs/style.rq" as styleguide.
The extension should resolve, cache, and validate remote imports.
Barrel imports should be recommended for token efficiency when many symbols are needed from one remote file.
from_import_syntax
reqlan rq/extension/language/support/features-imports.rq
Multiple symbols should be allowd to be be imported with `from "path" import symbol1, symbol2, symbol3` syntax.
Each imported name is its own link ( import_from ).
import_error
reqlan rq/extension/language/support/features-imports.rq
" Could not resolve reference " errors offer Quick Fix code actions ( lightbulb and editor right-click Quick Fix ).
Fixes:
- Add import from a matching idea found in loaded documents or the name catalog pushed from the index
- Rewrite the reference to an anonymous qualified form `path".name`
- Search the index for matching ideas, ideasets, or files ( same `reqlan.searchReference` path as code_actions / search_code_actions ), then insert an import
- Create the idea in a new. rq file and import it
general_errors
import_error
quick_fixes
- status
- done
- tests
- code-actions.test.ts, import-edits.test.ts, import-edits.test.ts:inserts after an existing different-path from-import with a blank line, import-edits.test.ts:inserts after an existing from-import with no blank line, import-edits.test.ts:inserts after an existing namespace import, import-edits.test.ts:inserts at the top when the file has no imports, import-edits.test.ts:appends to an existing same-path from-import, code_actions.rs:offers_add_import_and_rewrite_when_a_matching_idea_exists_elsewhere, code_actions.rs:uses_name_catalog_matches_when_documents_are_not_loaded, code_actions.rs:search_and_create_actions_invoke_extension_commands, code_actions.rs:appends_to_an_existing_from_import_for_the_same_path, code_actions.rs:appends_after_aliased_specifier_on_existing_from_import, code_actions.rs:offers_add_import_from_the_ideas_index, code_actions.rs:inserts_new_from_import_after_existing_from_import_with_blank_line, code_actions.rs:inserts_new_from_import_after_existing_from_import_without_blank_line, code_actions.rs:inserts_new_from_import_after_existing_namespace_import, code_actions.rs:inserts_from_import_at_top_when_file_has_no_imports
implicit_file_extension
reqlan rq/extension/language/support/features-imports.rq
The import statements should not require an extension, i. e. it should assume ". rq " unless otherwise specified.
An extensionless path resolves to the ". rq " file first, then to a literal extensionless file or folder.
A path that already carries any extension is resolved exactly as written.
Folder targets: import_folder_targets.
- implementation
- reqlan-imports.ts, reqlan-file-link-resolver.ts, reqlan-outbound-presentation.ts, reqlan-local-symbolic-links.ts
- tests
- implicit-import-extension.test.ts, outbound-hop.test.ts:confirms a neighbor idea when the authored path has no .rq extension
import_folder_targets
reqlan rq/extension/language/support/features-imports.rq
An import path may refer to a folder.
A folder is a valid import target when that path exists as a directory.
Namespace import of a folder binds the alias to that folder, the same as a file.
Extensionless paths still prefer a `.rq` file: implicit_file_extension.
Related: import_paths, import_does_not_exist_error, file_references.
- implementation
- reqlan-imports.ts, reqlan-file-link-resolver.ts, reqlan-validator.ts
- status
- done
- tests
- implicit-import-extension.test.ts:filesystem lookups append .rq then accept an existing directory, validating.test.ts:does not report an error when an import path is an existing folder, linking.test.ts:folder import paths produce folder document links
import_code_completion
reqlan rq/extension/language/support/features-imports.rq
Import path code completion for `import` / `from` strings ( and shared anonymous paths ).
code_completion
import_code_completion_explicit_extension
import_code_completion_path_segments
import_code_completion_substring_match
import_code_completion_ranking
anonymous_reference_code_completion
import_code_completion_auto_file_import
import_code_completion_rendering
import_code_completion_rendering
reqlan rq/extension/language/support/features-imports.rq
Reference code completion for ideas from other files shows the relative import path in the completion detail.
Same-file ideas omit the path detail.
reference_code_completion
import_code_completion
import_code_completion_auto_file_import
- implementation
- reqlan-completion-provider.ts
- status
- done
- tests
- completion.test.ts
import_code_completion_auto_file_import
reqlan rq/extension/language/support/features-imports.rq
When a code completion for an idea in another file is selected, the import should be automatically added to the current file.
This prevents the user from selecting a presented idea, and then having to add the import for the same thing.
Uses the same from-import insertion as import_error quick fixes; skips the edit when the idea is already imported.
reference_code_completion
import_code_completion
import_code_completion_rendering
import_error
- implementation
- reqlan-completion-provider.ts, reqlan-import-edits.ts
- status
- done
- tests
- completion.test.ts
import_code_completion_explicit_extension
reqlan rq/extension/language/support/features-imports.rq
Completions insert paths with an explicit `.rq` extension. implicit_file_extension
Hand-written imports may still omit the extension; completion prefers the written form with `.rq`.
- implementation
- reqlan-path-completion.ts, reqlan-completion-provider.ts
- tests
- completion.test.ts
import_code_completion_path_segments
reqlan rq/extension/language/support/features-imports.rq
In a folder context, show next path segments ( directories with a trailing `/` ).
After `../`, offer `../path/` before nested `../path/file.rq`.
- implementation
- reqlan-path-completion.ts, reqlan-completion-provider.ts
- tests
- completion.test.ts
import_code_completion_substring_match
reqlan rq/extension/language/support/features-imports.rq
Filter path candidates by search within the path, not only a starts-with prefix.
Typing `path` should match `../../parent/path.rq`.
Typing `hellopath` should match `../../hello/inbetween/path/file.rq` ( characters matched in order across path segments ).
- implementation
- reqlan-path-completion.ts, reqlan-completion-provider.ts
- tests
- completion.test.ts
import_does_not_exist_error
reqlan rq/extension/language/support/features-imports.rq
Imports show an underline error when the target file or folder does not exist.
Imports also show an underline error when a named imported idea does not exist in the target file.
An existing folder is not an error: import_folder_targets.
CI: check_unresolved_imports.
general_errors
- implementation
- reqlan-validator.ts, reqlan-imports.ts, broken.rs
- tests
- validating.test.ts, validating.test.ts:does not report an error when an import path is an existing folder, broken_references.rs:check_reports_missing_import_path, broken_references.rs:check_reports_missing_imported_idea
import_code_completion_ranking
reqlan rq/extension/language/support/features-imports.rq
Rank import path completions by directory proximity ( hop count from the completing file's directory to the candidate's directory ), then directories before files, then path alphabetically.
Example: typing `../` ranks `../close.rq` before `../../../path.rq`.
Emit sortText for that order, and set filterText so the editor does not re-rank by label fuzzy score over proximity.
- implementation
- reqlan-path-completion.ts, reqlan-completion-provider.ts
- tests
- completion.test.ts
anonymous_reference_code_completion
reqlan rq/extension/language/support/features-imports.rq
Anonymous imports should share the same code completion
e. g. features-syntax.rq should complete the same as `import "@/reqlan rq/extension/language/syntax/features-syntax.rq" as code_completion`. they should share the same code and logic
lsp_file_watch
reqlan rq/extension/language/support/initialisation-and-sequencing.rq
The language server must register workspace file watchers for `.rq` files only.
It must not register a recursive all-files watcher.
Watched-file events whose path contains a `node_modules`, `.git`, `.reqlan`, `out`, or `dist` segment must not start a document rebuild.
Directory URIs without a trailing slash, Windows paths, and percent-encoded URIs must use the same segment rules.
A kept `.rq` change replaces that buffer's model when the text changed ( ast_lifecycle ).
Related: language_server, index_file_search_coalesce, open_file_algorithm.
- implementation
- reqlan-document-update-handler.ts, reqlan-module.ts
- status
- done
- tests
- document-update-watch.test.ts, document-update-watch.test.ts:registers .rq globs only, document-update-watch.test.ts:classifies Windows and directory URIs by path segment, document-update-watch.test.ts:drops noisy events and keeps .rq files, ast-lifecycle.test.ts:replaces the AST when this buffer text changes
index_file_search_coalesce
reqlan rq/extension/language/support/initialisation-and-sequencing.rq
Index startup does not call `findFiles` or ripgrep / `searchtext.exe`.
The native workspace scan ( single_sync_walk ) is the one directory walk.
Overlapping rediscover and sync callers share that in-flight scan.
The scan applies `.rqignore` ( nonblocking_index ).
Related: lsp_file_watch, rqignore, scan_limits.
- implementation
- share-in-flight.ts, index-service.ts
- status
- done
general_errors
reqlan rq/extension/language/support/language-server-errors.rq
error messages should be deliberate and developer friendly.
recommendations should be offerred where appropriate.
file_reference_errors
reqlan rq/extension/language/support/language-server-errors.rq
If a file_reference is not found, is broken, or cannot be resolved, the language server must show an underline.
Do not show the underline when comment_reference_ignore ( `//rq-ignore-error` ) is on the line before.
Missing files: error underline, no document link.
Do not underline examples inside inline_code or code_snippets.
Empty files and files with parse errors: warning underline; the document link stays.
Import-root aliases such as `@/` resolve the same way as check and configuration_import_root_alias.
Related: general_errors, comment_reference_resolution_error, inline_code,
import_does_not_exist_error,
file_references.
- implementation
- reqlan-validator.ts, reqlan-file-link-resolver.ts, reqlan-document-link-provider.ts, reqlan-ignore-error.ts, reqlan-embedded-file-references.ts, analysis.rs, path_resolve.rs
- status
- done
- tests
- linking.test.ts:missing file references do not produce document links, rq-ignore-error, linking.test.ts:remote file references are not reported as missing, linking.test.ts:empty file references produce document links and warning diagnostics, linking.test.ts:parse-error file references produce document links and warning diagnostics, ignore-error.test.ts:reports a missing file reference as an error, rq-ignore-error, ignore-error.test.ts:does not report file references inside inline code, parity.rs:import_root_alias_file_refs_match_check, parity.rs:import_root_config_file_refs_match_check, broken_references.rs:check_accepts_import_root_alias_file_refs, broken_references.rs:check_honours_import_roots_from_applying_config
language_server_rust
reqlan rq/extension/language/support/language-server-rust.rq
A Rust binary replaces the Langium language-server process.
The extension launches `reqlan-lsp` over stdio.
Open `.rq` buffers parse with parser_rust.
The open sequence is open_file_algorithm.
Workspace names and rename targets come from the ideas index under application_memory.
Inbound hints wait for the host snapshot of that index.
The inbound inlay hover is markdown. It lists each referencer as a file link.
An idea hover shows styled idea content when idea_content_tooltip is on.
A closed file has no retained syntax tree.
Go-to-definition cost is reference_goto_definition_speed.
When the engine is `rust`, the server also serves `rq:…` document links, go-to-definition, and missing-idea diagnostics in non- `.rq` comments.
One resolution supplies the link, the definition target, and the underline.
The host strips file document links; Ctrl + click uses definition ( editor_reference_activation ).
The host serves those links when the engine is `node`.
Host commands prefer LSP custom requests, napi extract, and the ideas index.
Move / delete planners still use Langium until index-backed planners land.
The setting `reqlan.languageServer.engine` selects the binary.
The default is `rust`.
`node` remains only when the setting says so, or when the binary is not on disk yet.
A local extension build compiles this binary with the napi addon ( extension_host_native_stage ).
The extension launches `bin/reqlan-lsp`, else that release build. It never launches a debug build, because a debug build is slow and the extension build does not refresh it.
Code actions match code_actions: ignore, create below, import fixes, search or wrap, idea move and delete, and barrel page.
Attribute and name catalogs drive completion. Rename and find-references use open buffers plus the ideas index.
Inlay hints honour `reqlan.referencesInlayHints.enabled` and the host inbound snapshot.
An import link uses the parser token span ( import_from ).
The path links to the file.
An imported idea name and its alias each link to that declaration.
A namespace reference links the alias and the idea as separate names.
A missing leaf reports an unresolved idea on that name.
Related: language_server, grammar_and_parser, analytical_rust_port, vsix_export.
- implementation
- lib.rs, server.rs, session.rs, analysis.rs, hover_content.rs, code_actions.rs, language-server-launch.ts, main.ts, collect-napi-binary.mjs, stage-host-native.mjs, package-extension-targets.mjs, azure-pipelines.yml
- plan
- goal
A Rust language-server binary replaces the Langium process. Open buffers parse with reqlan-parse. Workspace names come from the ideas index. Closed files have no retained syntax tree.
constraints
- vscode-languageclient stays. Transport becomes stdio.
- lsp-server and lsp-types only. No second parser.
- Open-file links follow open_file_algorithm.
- UTF-8 spans convert to UTF-16 LSP positions.
- TextMate stays a checked-in grammar. The editor paints it before semantic tokens.
- With the rust engine, non-.rq comment links come from the server. The node engine keeps the host provider.
- Per-target VSIX ships bin/reqlan-lsp. The napi addon stays for the index host.
- Default engine is rust. Node starts only as a fallback.
steps
1. Write this idea and point language_server and grammar_and_parser at it.
2. Scaffold reqlan-lsp: initialize, didOpen, didChange, didClose, parse diagnostics.
3. Launch it from the extension. Default is rust.
4. Port open-file features: tokens, links, definition, hover, highlight, diagnostics.
5. Read the ideas index for completion, rename, code actions, lenses, and inlays.
6. Pack the binary in the VSIX matrix.
7. Keep Langium only for host helpers. The server process does not load it when the engine is rust.
open
- Host move/delete/barrel planners still use Langium DI. - status
- in-progress
- tests
- session.rs:open_file_diagnostics_and_close_drops_the_parse, session.rs:semantic_token_range_matches_the_source_name, session.rs:definition_hover_highlight_and_link, session.rs:definition_uses_the_open_neighbor_parse, session.rs:definition_does_not_reread_a_cached_neighbor, session.rs:folder_reference_link_is_a_command, hover_content.rs:hover_shows_styled_idea_content_by_default, hover_content.rs:hover_omits_idea_content_when_the_setting_is_off, hover_content.rs:hover_shows_idea_content_from_another_file, session.rs:neighbor_confirm_suppresses_missing_idea, session.rs:rq_ignore_suppresses_the_next_line, session.rs:completion_rename_and_code_action, session.rs:index_completion_inlay_and_custom_requests, session.rs:attribute_catalog_completion_and_find_references, stdio.rs:stdio_initialize_and_shutdown, parity.rs:same_file_idea_references_produce_document_links, parity.rs:missing_file_references_do_not_produce_document_links, parity.rs:import_root_alias_file_refs_match_check, parity.rs:import_root_config_file_refs_match_check, parity.rs:anonymous_import_path_does_not_report_an_unresolved_import, parity.rs:reports_an_error_when_an_import_path_file_does_not_exist, parity.rs:reports_an_error_when_an_imported_idea_does_not_exist, parity.rs:anonymous_qualified_idea_resolves_without_an_import_statement, parity.rs:quoted_path_reaches_an_idea_that_is_not_from_imported, parity.rs:extensionless_path_confirms_the_neighbor_idea, parity.rs:from_import_binds_a_local_reference, parity.rs:from_import_tokens_link_independently, parity.rs:import_document_link_covers_the_path_string, parity.rs:namespace_drill_links_each_segment, parity.rs:namespace_drill_missing_leaf_is_unresolved, parity.rs:namespace_alias_is_a_file_link, parity.rs:formats_inbound_referencers_as_an_inlayed_attribute, parity.rs:truncates_long_referencer_lists_with_a_remainder_suffix, parity.rs:omits_the_inlay_when_there_are_no_inbound_referencers, session.rs:comment_links_share_one_resolution, session.rs:comment_definition_follows_a_resolved_rq_reference, language-server-launch.test.ts:defaults to the rust binary over stdio, language-server-launch.test.ts:launches the release build and never a debug build, code_actions.rs:offers_ignore_error_quick_fix_on_a_line_with_a_linking_error, code_actions.rs:omits_ignore_error_when_only_refactor_is_requested, code_actions.rs:creates_the_missing_idea_below_the_containing_idea, code_actions.rs:offers_all_or_a_specific_unresolved_idea, code_actions.rs:omits_create_below_when_the_caret_idea_has_no_unresolved_local_references, code_actions.rs:omits_create_below_for_a_qualified_unresolved_reference, code_actions.rs:omits_create_below_when_only_refactor_is_requested, code_actions.rs:offers_add_import_and_rewrite_when_a_matching_idea_exists_elsewhere, code_actions.rs:uses_name_catalog_matches_when_documents_are_not_loaded, code_actions.rs:search_and_create_actions_invoke_extension_commands, code_actions.rs:appends_to_an_existing_from_import_for_the_same_path, code_actions.rs:offers_add_import_from_the_ideas_index, code_actions.rs:offers_search_code_action_when_cursor_is_inside_a_resolved_reference, code_actions.rs:offers_wrap_code_action_for_a_prose_selection, code_actions.rs:wraps_the_word_under_the_cursor_when_selection_is_empty, code_actions.rs:offers_move_and_delete_actions_at_an_idea_declaration, code_actions.rs:offers_barrel_page_source_action_when_the_file_has_top_level_ideas, code_actions.rs:omits_barrel_page_when_only_quickfix_is_requested_or_there_are_no_ideas
- todo
- Move/delete and barrel-page host planners still call Langium DI. Finish those off napi/index/LSP.
open_file_algorithm
reqlan rq/extension/language/support/open-file-sequencing.rq
When the editor opens or changes a `.rq` buffer, `reqlan-lsp` runs this sequence.
Do not wait for the ideas index. Do not wait for a workspace crawl.
Detail: open_file_sequence_diagram.
Related: open_file_reference_sequencing, language_server_rust, ast_lifecycle,
outbound_one_hop, open_file_hot_path, token_colour_sequence,
missing_reference_colour_sequence, lazy_features_after_outbound.
The hot path finishes before the first diagnostics publish.
1. Parse this buffer once ( open_file_algorithm ).
2. Colour tokens from that parse ( token_colour_sequence ).
3. Emit same-file links and same-file missing-idea errors from that parse.
4. Parse each imported file once, at depth 1, for idea names and lines ( open_file_algorithm ).
Link an imported name that exists. Underline an imported name that does not
( missing_reference_colour_sequence ).
5. Return. A qualified reference may link to its file from the path token.
Do not read that file on this path.
After that publish, a background pass fills the rest ( open_file_algorithm ).
That pass must not delay steps 1 – 5.
The server sends the hot publish before it starts that pass.
It runs that pass only while no client message waits. A hover or a definition request goes first.
A change reuses the import roots loaded at open. It does not read the config again.
The node engine keeps node_engine_open_path.
- implementation
- session.rs, analysis.rs, server.rs
- status
- done
- tests
- session.rs:semantic_token_range_matches_the_source_name, parity.rs:same_file_idea_references_produce_document_links, parity.rs:from_import_binds_a_local_reference, parity.rs:reports_an_error_when_an_imported_idea_does_not_exist, workspace link
open_file_sequence_diagram
reqlan rq/extension/language/support/open-file-sequencing.rq
open_file_algorithm
Actors: VS Code editor, TextMate grammar, extension host, `reqlan-lsp`, file system.
ast_lifecycle
reqlan rq/extension/language/support/open-file-sequencing.rq
The open buffer has one model. That model is the Rust parse of this buffer.
local_symbolic_analysis is a file-local extract. The hot path does not run it as a second parse.
Related: open_file_algorithm, open_file_sequence_diagram, outbound_one_hop,
token_colour_sequence, parse_budget_timeout,
lsp_file_watch, language_server_rust.
Populate. Parse this buffer when the editor opens it.
Semantic tokens, same-file links, and the import list come from that parse.
Replace. When this buffer text changes, parse again and replace the model.
Do not patch the old model. A watched `.rq` change uses the same replace path
( reqlan-document-update-handler.ts ). When the text is unchanged, keep the current model.
Drop. When the editor closes the buffer, drop the model.
A closed file keeps no syntax tree ( language_server_rust ).
Import files. outbound_one_hop stores a name list for each imported file.
That list is not an open-buffer model.
A change to an imported file does not replace this buffer's model.
Read the imported file again when its content hash changes.
Incomplete parse. When the budget fails, store an empty model plus diagnostics
( ast_lifecycle ). Idea names stay empty until a later successful parse.
The node engine follows node_engine_open_path.
- implementation
- session.rs, analysis.rs, server.rs
- status
- done
- tests
- session.rs:open_file_diagnostics_and_close_drops_the_parse, parse-budget.test.ts:times out a hung parse worker with warning and error
token_colour_sequence
reqlan rq/extension/language/support/open-file-sequencing.rq
Token colour has two layers. They must not wait for the ideas index.
TextMate paints first from the buffer text. Semantic tokens paint from the one parse
( ast_lifecycle ). A second extract does not paint tokens.
A missing reference keeps the same token colour. The error underline is a diagnostic
( missing_reference_colour_sequence, reference_rendering ).
Related: syntax_highlighting.
- implementation
- reqlan.tmLanguage.json, reqlan-semantic-token-provider.ts, analysis.rs, main.ts
- status
- done
- tests
- textmate-import-highlight.test.ts, semantic-tokens-wildcard.test.ts, session.rs:semantic_token_range_matches_the_source_name
file_crawl_sequence
reqlan rq/extension/language/support/open-file-sequencing.rq
Workspace crawl is the indexer ( index, index_sequencing ). It is not the open-file path.
Native sync walks `.rq` files, then allowlisted code files, and writes SQLite.
Open-file links must not wait for that walk ( open_file_algorithm ).
The language server watches `.rq` files only ( lsp_file_watch ).
Related: extension_startup_sequence, background_startup.
- implementation
- workspace-index.ts, sync.rs, register-inbound-sqlite-sync.ts, server.rs
- status
- done
outbound_one_hop
reqlan rq/extension/language/support/open-file-sequencing.rq
The hot path parses imported files only.
For each import in the open buffer, parse that file once, then stop.
Read idea names, idea lines, and import aliases. Do not parse files that the import references.
Do not read SQLite.
Prefer the open buffer text when that import is already open and dirty.
Cache each parse by path plus file stamp ( modified time and size ) ( session.rs ).
A current stamp is one `stat`. Read and parse the file only when the stamp changed.
Cache the open buffer by URI plus text fingerprint ( open_file_hot_path ).
local_symbolic_analysis stays file-local. This hop is outside that extract.
An extensionless import path prefers `.rq`, then the path as written
( implicit_file_extension ).
A qualified reference that is not an import waits for lazy_features_after_outbound.
Related: open_file_algorithm, non_web_reference_navigation.
- implementation
- session.rs, analysis.rs, parse-source.ts
- status
- done
- tests
- parity.rs:from_import_tokens_link_independently, parity.rs:reports_an_error_when_an_import_path_file_does_not_exist, parity.rs:extensionless_path_confirms_the_neighbor_idea, outbound-hop.test.ts:reuses a cached neighbor parse for the same content, outbound-hop.test.ts:does not parse a neighbor of the neighbor
open_file_hot_path
reqlan rq/extension/language/support/open-file-sequencing.rq
Open-file work stays on the one parse of this buffer plus one parse per imported file.
Reuse that model for document links, go-to-definition, hover, and diagnostics until the text
or the import-root mapping changes.
Keep that model, and the import name lists, only for open editors ( native_cache_retention ).
Look up an open import by URI. Do not match on file basename.
Do not read SQLite. Do not call `list_all_ideas`.
At parse time, publish lex and parse diagnostics with same-file and import errors.
The editor must not wait for a workspace link phase to see a broken parse.
Handlers on this path read the open model. They do not build a workspace link graph.
Related: open_file_algorithm, outbound_one_hop, ast_lifecycle,
comment_backlink_sequence.
- implementation
- session.rs, analysis.rs, server.rs
- status
- in-progress
- tests
- open-file-hot-path.test.ts:reuses the host native extract for links and diagnostics, open-file-hot-path.test.ts:reparses the host native extract when this buffer text changes, open-file-hot-path.test.ts:does not treat a same-name file as the loaded neighbor, parity.rs:same_file_idea_references_produce_document_links
- todo
- Unqualified comment lookup can still fall back to the name catalog when no open buffer matches.
missing_reference_colour_sequence
reqlan rq/extension/language/support/open-file-sequencing.rq
Paint links and errors in two steps.
The hot path paints same-file names and import targets ( outbound_one_hop ).
The background pass paints qualified-reference idea lines ( lazy_features_after_outbound ).
Related: unresolved_reference_diagnostics, reference_rendering,
file_reference_errors, import_does_not_exist_error.
Hot path:
- URL references: document link, no error.
- Wildcard references: document link, no error underline for zero matches.
- Import path missing: error underline, no document link.
- Imported idea present: document link to that idea line.
- Imported idea missing: error underline, no document link.
- Same-file idea missing: error underline, no document link.
- Qualified reference: document link to the file from the path token.
Do not underline a missing idea yet.
Background pass:
- Qualified idea present: document link to that idea line.
- Qualified idea missing: error underline, and remove the document link.
- Drop a false missing-idea error only for the range that this pass confirms.
Keep a different missing name on the same line.
- implementation
- analysis.rs, session.rs, reqlan-outbound-presentation.ts, reqlan-document-link-provider.ts
- status
- done
- tests
- parity.rs:missing_file_references_do_not_produce_document_links, outbound-hop.test.ts:keeps URL and wildcard document links, outbound-hop.test.ts:keeps a missing idea error on the same line as a confirmed neighbor idea, local-symbolic-links.test.ts:unresolved same-file ideas get no document link
comment_backlink_sequence
reqlan rq/extension/language/support/open-file-sequencing.rq
`rq:idea` and `rq:idea` in code comments use one resolution for the link and the underline.
A qualified path reads that `.rq` file, parses idea names, then links or errors.
That read belongs to the comment file. Opening a different `.rq` buffer must not re-resolve every comment buffer.
An unqualified name searches open `.rq` buffers first.
The index snapshot may add a match later ( lazy_features_after_outbound ).
Do not call `list_all_ideas` for that search.
Do not create a document link when the idea is not confirmed.
Related: comment_reference_resolution_error_state.
- implementation
- session.rs, reqlan-comment-diagnostics.ts, register-comment-reference-links.ts, reqlan-comment-resolver.ts
- status
- in-progress
- tests
- session.rs:comment_links_share_one_resolution, comment-reference-resolution.test.ts:reports a missing comment reference idea in a loaded file, comment-reference-resolution.test.ts:shares one presentation so a matching idea clears the underline and adds a link
- todo
- A change to a .rq file still republishes every comment buffer in the background pass, and unqualified lookup can call list_all_ideas.
lazy_features_after_outbound
reqlan rq/extension/language/support/open-file-sequencing.rq
After the hot path is on screen, show the rest when its data is ready.
This pass must not delay open_file_algorithm steps 1 – 5.
Related: language_server, unify_inbound_indexes, background_startup,
inlay_hints, codelens.
Work:
- Confirm each qualified reference. Read that target file once, at depth 1.
Then paint the idea line or the missing-idea error ( missing_reference_colour_sequence ).
- Inbound backlinks: inlay hints and the file-top CodeLens, from the host snapshot
( unify_inbound_indexes ).
- Attribute and name catalogs for completion and quick fixes.
- Unqualified comment matches from that snapshot ( comment_backlink_sequence ).
Until the first ready snapshot arrives, inlay hints and the file CodeLens stay empty.
Those handlers do not open SQLite and do not call `list_all_ideas`.
Later updates are incremental ready-state events
( inbound_snapshot_events ); last-good stays until replaced.
When a ready snapshot arrives, refresh the visible editors.
- implementation
- session.rs, server.rs, register-inbound-sqlite-sync.ts, main.ts
- status
- done
- tests
- inbound-referencer-index-perf.test.ts:inlay referencers come from the pushed snapshot, not findAllReferences, session.rs:index_completion_inlay_and_custom_requests, session.rs:neighbor_confirm_suppresses_missing_idea, parity.rs:formats_inbound_referencers_as_an_inlayed_attribute
native_cache_retention
reqlan rq/extension/language/support/open-file-sequencing.rq
The language server keeps the open-buffer model for each open editor.
It keeps a depth-1 name list for each imported file, and for each qualified-reference file
the background pass has confirmed, while an open editor still needs that list.
A closed editor drops its model. It also drops name lists that no open editor still needs.
A file-watcher delete drops that URI from both caches.
A check of a closed file may parse it once. That result is not stored.
Related: open_file_hot_path, outbound_one_hop, ast_lifecycle.
- implementation
- session.rs, reqlan-editor-retention.ts, reqlan-neighbor-parse.ts, reqlan-document-update-handler.ts
- status
- done
- tests
- session.rs:open_file_diagnostics_and_close_drops_the_parse, lsp-memory.test.ts:drops a neighbor list when the last open editor closes, lsp-memory.test.ts:drops a neighbor list when the file watcher reports a delete, outbound-hop.test.ts:reuses a cached neighbor parse for the same content
node_engine_open_path
reqlan rq/extension/language/support/open-file-sequencing.rq
This idea applies when `reqlan.languageServer.engine` is `node`.
The default engine is language_server_rust.
The node server populates a Langium AST for the open buffer at `DocumentState.Parsed`.
Later builder phases attach scopes, links, and diagnostics. They must not replace that AST.
Parsed-time handlers must not read Langium `.ref`.
Use `$refText`, the symbolic extract, or `peekResolvedRef` until `ComputedScopes`.
The linker must not resolve a cross-reference while that document is below `ComputedScopes`.
Do not log the Langium warning. Do not store a failed link.
Scope lookup, code lens, completion, and idea summaries use `readResolvedRef` or `peekResolvedRef` until that phase.
When another `.rq` file changes, relink this document when the index says it is affected,
when comment references name that file, or when this document's outbound targets include the changed URI.
Do not relink every document that still has a linker error.
Workspace load parses at most 8 files at a time ( workspace_parse_concurrency ).
`fileIdeasCache` and `importPathCache` drop a URI when that document is removed ( scope_cache_release ).
Related: open_file_algorithm, ast_lifecycle.
- implementation
- reqlan-document-factory.ts, reqlan-document-builder.ts, reqlan-async-parser.ts, reqlan-parse-budget.ts, reqlan-workspace-manager.ts, reqlan-scope.ts, reqlan-local-symbolic-links.ts, reqlan-neighbor-parse.ts, reqlan-outbound-presentation.ts, reqlan-document-link-provider.ts, main.ts, reqlan-linker.ts, reqlan-reference-peek.ts
- status
- done
- tests
- ast-lifecycle.test.ts:populates the Langium AST at Parsed without DocumentBuilder, ast-lifecycle.test.ts:linking and validation do not replace the AST, ast-lifecycle.test.ts:neighbor hop does not populate a Langium AST, parsed-reference-sequencing.test.ts:definition hover highlight and links do not resolve refs before ComputedScopes, parsed-reference-sequencing.test.ts:reading every ref before ComputedScopes does not warn and linking still works, open-file-hot-path.test.ts:does not relink an unrelated file that still has linker errors, open-file-hot-path.test.ts:relinks a host when its neighbor file changes
scope_cache_release
reqlan rq/extension/language/support/open-file-sequencing.rq
This idea applies when the engine is `node` ( node_engine_open_path ).
`fileIdeasCache` and `importPathCache` drop a URI when that Langium document is removed.
A version change still replaces the entry for a document that stays.
The rust server drops the open model in native_cache_retention.
Related: open_file_hot_path, native_cache_retention.
- implementation
- reqlan-scope.ts
- status
- done
- tests
- lsp-memory.test.ts:drops scope cache entries when a document is removed
workspace_parse_concurrency
reqlan rq/extension/language/support/open-file-sequencing.rq
This idea applies when the engine is `node` ( node_engine_open_path ).
Workspace load parses `.rq` files with a fixed limit of 8 in flight.
One file that fails to parse does not cancel the other files.
The steady-state set is still every workspace `.rq` file.
The rust server does not parse the workspace. A closed file keeps no syntax tree
( language_server_rust ).
Related: ast_lifecycle, reqlan-workspace-manager.ts.
- implementation
- reqlan-workspace-manager.ts
- status
- done
- tests
- lsp-memory.test.ts:runs at most the concurrency limit, lsp-memory.test.ts:loads every workspace file with at most 8 parses in flight
complementary_information_rendering
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
The extension should render computed information inline in the editor as complementary text.
Complementary rendering should include resolved references and optionally indirect references behind a toggle.
Complementary rendering should not mutate source files unless the user explicitly applies a change.
reference_rendering
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
Resolved references should be visually distinguishable from unresolved or broken references.
Indirect references inferred by graph traversal should be showable via a user toggle.
Reference kinds ( dependency, incompatible with, applies to, related to ) should be surfaced where declared or inferred.
Unresolved idea and file references must keep a linking / missing-file diagnostic ( error underline ).
They must not receive a document-link underline that makes them look like happy, navigable references.
See import_statement_highlighting, non_web_reference_navigation, unresolved_reference_diagnostics.
import_statement_highlighting
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
TextMate highlighting for import lines must colour the whole statement, not only the leading
`from` / `import` keyword. After `import` ( and after `from` … `import` ), the quoted path,
the `import` / `as` keywords, and idea / alias names must receive scopes — they must not stay
default-white while still looking interactive from a path document link alone.
Root cause: a short `^\\b(from|import)\\b` match ran before the path patterns and consumed the
keyword so the path never scoped.
Fix: line-scoped `meta.import.reqlan` begin / end rules that paint path, keywords, and names.
Semantic tokens still paint import AST nodes ( and must `return` after handling them ).
- status
- done
- tests
- textmate-import-highlight.test.ts, textmate-import-highlight.test.ts:e2e: from-import line scopes path and import keyword, textmate-import-highlight.test.ts:e2e: namespace import line scopes path and as
non_web_reference_navigation
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
Non-web references ( idea brackets / wikilinks, local file paths, import paths ) must be Ctrl + click
navigable via document links and / or go-to-definition. Built-in http ( s ) link detection is not enough.
The rust engine builds same-file links and import-target links on the open path
( open_file_reference_sequencing,
outbound_one_hop ).
When the engine is node, idea underlines use the path-local Rust extract
( local_symbolic_analysis ),
and go-to-definition uses Langium when the idea ref is already linked.
Qualified-reference idea lines follow
lazy_features_after_outbound.
Related: reference_document_links, reference_goto_definition_speed,
reference_underline_syntax_align,
open_file_reference_sequencing.
unresolved_reference_diagnostics
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
Unresolved idea references must report a linking error diagnostic.
A same-file miss and an import-target miss have an error and no document link.
A qualified reference may link to its file before the idea line is confirmed.
After confirmation, a missing idea has an error and no document link
( missing_reference_colour_sequence ).
A false idea link looked like a happy reference while Ctrl + click could not navigate.
Missing file references stay on file_references /
file_reference_errors ( error, no document link ).
Related: reference_rendering, non_web_reference_navigation.
- implementation
- reqlan-local-symbolic-links.ts, reqlan-neighbor-parse.ts, reqlan-outbound-presentation.ts, reqlan-document-link-provider.ts, analysis.rs, reqlan-validator.ts
- status
- in-progress
- tests
- local-symbolic-links.test.ts:unresolved same-file ideas get no document link, outbound-hop.test.ts:does not link when the neighbor file exists but the idea is missing, outbound-hop.test.ts:drops a false unresolved diagnostic when the neighbor idea exists, ignore-error.test.ts:reports unresolved reference without ignore directive
- todo
- The qualified file link before idea confirmation is still open on missing_reference_colour_sequence.
reference_document_links
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
Bracket and wikilink idea references — both same-file and cross-file — must emit a document link
so the editor can follow them the same way as file-path references.
Editor activation is editor_reference_activation.
All resolved `LocalReference` and `QualifiedReference` idea / ideaset tokens should emit links targeting the
declaration name, regardless of whether the target lives in the same file or an imported one.
Namespace-import alias tokens ( `alias` → file ) keep their existing file-target link.
Each link must include a `target` and a `tooltip` so VS Code does not show " Loading... ".
Implemented by reqlan-file-link-resolver.ts
( `resolveIdeaReferenceLinks`, `collectFileLinks` ) and
reqlan-document-link-provider.ts.
- status
- done
- tests
- linking.test.ts:same-file idea references produce document links, linking.test.ts:cross-file imported idea references produce document links, linking.test.ts:qualified reference idea token produces document link, linking.test.ts:navigable document links include target and tooltip, local-symbolic-links.test.ts:aliased from-import whose name contains the imported idea is one link
editor_reference_activation
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
A file reference and an idea reference have no underline in the resting editor.
The editor shows an underline when the user holds Ctrl and the pointer is on that reference.
Ctrl + click follows the reference in the active editor.
A target in the open file moves the cursor in that editor.
A target in another file opens in the active editor group.
The editor does not open a second copy of the current file.
The editor does not open a browser page for a file or idea reference.
Alt + Left is navigate-back. It restores the caret from before go-to-definition.
The extension keeps that JUMP on a reqlan stack because Cursor often skips the editor history entry for same-file definition.
The stack also records jumps that start in comment-reference host languages
( comment_reference_navigate_back ).
Definition targets prefer an open workspace tab URI so Cursor does not open a detached file copy.
The definition target range must move the caret ( not an empty 0: 0 – 0: 0 range ).
A click that is already on the declaration name is not a JUMP.
The TextMate scope is `meta.link.reqlan`.
A `markup.underline` scope forces an underline in the resting editor.
`.rq` file and idea references omit `markup.underline` — no resting underline.
Comment `rq:…` sites add `markup.underline` via the comment injection grammar
( comment_reference_resting_underline ).
A file document link is always underlined, and its `#L` URI opens another editor.
The extension does not give the editor a file document link.
Ctrl + hover uses the definition request. That request is reference_goto_definition_speed.
The interactive underline is the lexer token under the cursor: the path string or the idea id from the parser.
Definition returns `LocationLink.originSelectionRange` for that token so the editor does not invent a word from brackets or quotes.
Path segment names inside a quoted path are not reference tokens.
The host does not register a DefinitionProvider for other languages, and does not rescan open source files for this activation.
When the engine is rust, the language-server document selector includes all file-scheme documents except the comment-host blocklist, and definition navigates resolved `rq:…` sites
( references_in_functional_code_comments,
comment_reference_language_blocklist ).
A web URL and a command link ( folder, wildcard ) stay document links.
A click on a web URL opens that URL in the browser.
Related: reference_document_links, non_web_reference_navigation, editor_reference_activation.
- implementation
- patch-textmate.mjs, reqlan.tmLanguage.json, reqlan-comment.injection.json, language-configuration.json, editor-link-activation.ts, register-editor-link-activation.ts, definition-navigation.ts, definition-navigation-stack.ts, register-definition-navigation.ts, main.ts, analysis.rs, session.rs
- status
- done
- tests
- textmate-wildcard-highlight.test.ts:reference rules use the meta.link scope, editor-link-activation.test.ts:keeps web URL and command document links, editor-link-activation.test.ts:editor words are identifiers; reference tokens come from the parser, editor-link-activation.test.ts:go-to-definition does not send the buffer, editor-link-activation.test.ts:comment injection link scope includes markup.underline, editor-link-activation.test.ts:package.json contributes comment.rq.injection, definition-navigation.test.ts:records a command selection move as a definition jump, definition-navigation.test.ts:records a cross-file command jump from the prior caret, definition-navigation.test.ts:tracks non-blocklisted languages for navigate-back, definition-navigation.test.ts:records only landings in reqlan targets, definition-navigation.test.ts:navigate-back keybinding is not limited to .rq editors, session.rs:definition_origin_is_the_lexer_token_under_the_cursor, session.rs:comment_definition_follows_a_resolved_rq_reference
aliased_from_import_ctrl_click
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
A from-import alias that contains the imported idea name as a suffix or substring
must offer one Ctrl + click destination for the whole written alias.
Example: `from "@/_charter/plant-ontology.rq" import simulation as ontology-simulation`
then `ontology-simulation`.
The document-link underline must cover `ontology-simulation`, not only `simulation`.
Ctrl + click on any character of that alias must open the imported idea in the import-root
target file.
Do not resolve the import path a second time against the current file directory.
Do not offer a second interactive link on the original idea-name suffix.
Related: reference_document_links, reference_underline_syntax_align,
non_web_reference_navigation,
import_from,
configuration_import_root_alias.
- implementation
- reqlan-local-symbolic-links.ts, reqlan-imports.ts, extract.rs
- status
- done
- tests
- local-symbolic-links.test.ts:aliased from-import whose name contains the imported idea is one link, local_symbolic.rs:analyze_local_symbolic_aliased_from_import_keeps_authored_path_and_written_name
reference_underline_syntax_align
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
Idea document-link and error underlines must cover the same UTF-16 range as the
syntax token ( Langium `$refNode` / semantic token ), including when non-ASCII text
appears earlier in the file.
Native extract spans are UTF-8 byte offsets
( local_symbolic_analysis ); LSP `Position.character`
is UTF-16. Convert before `positionAt` so the underline does not drift off the token.
Related: non_web_reference_navigation, reference_document_links,
unresolved_reference_diagnostics, aliased_from_import_ctrl_click.
- implementation
- reqlan-utf8-lsp-offset.ts, reqlan-local-symbolic-links.ts, reqlan-outbound-presentation.ts, types.rs
- status
- done
- tests
- utf8-lsp-offset.test.ts, local-symbolic-links.test.ts:idea underlines match syntax tokens after non-ASCII text, local_symbolic.rs:analyze_local_symbolic_source_offsets_are_utf8_bytes
same_line_named_block_highlighting
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
TextMate-only highlighting ( no semantic tokens ) must follow the canonical lexer for
named `{` / `}`: a top-level `name {}` or `name {hello}` is a complete
block_idea on that line. The grammar must close on the same line. It must not leave a block
open until a later own-line `}`. An open block swallows later one-liners such as
a name-only idea.
`name {` at end of line is a multiline block. Close it only on an own-line `}` so
matching prose pairs at end of line ( `{{SITE_URL}}` ) stay in the body per
nested_curly_braces.
`name text {braces}` is a simple_idea. `{` after other body text must not start a block.
TextMate idea-name scopes on a file must match the Langium parse of that file.
- implementation
- patch-textmate.mjs, reqlan.tmLanguage.json
- status
- done
- tests
- textmate-idea-highlight.test.ts, textmate-idea-highlight.test.ts:same-line named block rule closes on the opening line, textmate-idea-highlight.test.ts:e2e: same-line named braces do not swallow later ideas, textmate-idea-highlight.test.ts:e2e: TextMate idea names match the Langium parse, parsing.test.ts:same-line braces after a name parse as a block
wildcard_reference_highlighting
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
Bracket and wikilink forms of wildcard_references
( `*.rq".idea_*`, `label` ) must TextMate-scope as
`meta.link.reqlan` with the path as `string.other.link.reqlan` — never as
`comment.block.reqlan`. The grey " comment " paint happened when `#bracket-references` only
allowed ID suffixes, so `/*` inside an unmatched path opened a block comment.
Fixes: TextMate `#bracket-references` / wiki path patterns accept `WILDCARD_NAME` suffixes;
`#comments` block begin rejects empty slash-star-star-slash; body rules try references before
comments. Semantic tokens paint `WildcardReference.pathPattern` as string and `ideaPattern`
as variable ( syntax_highlighting ).
Related: comments, wildcard_references_webview.
- status
- done
- tests
- textmate-wildcard-highlight.test.ts, textmate-wildcard-highlight.test.ts:e2e: bracket wildcard path ref matches link scope and not block comment, semantic-tokens-wildcard.test.ts, semantic-tokens-wildcard.test.ts:e2e: WildcardReference emits string + variable tokens, glob survives tokenize → parse in prose, naked quotes, and reference STRING
reference_goto_definition_speed
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
Hover and go-to-definition are lookups on the open parse.
The parse keeps its references sorted by start byte. A request finds the reference under the cursor by binary search.
A request does not walk the syntax tree and does not convert each reference to a line and column.
A request resolves each authored path once per parse. It does not `stat` that path again.
A same-file idea uses that parse.
An open neighbor uses that neighbor's buffer.
A closed neighbor is parsed once. The server keeps its model, idea names, and name-token ranges.
A later request does one `stat`. It reads and parses the file again only when the modified time or the size changed.
A hover on a cross-file idea renders from that cached model. It does not read the file.
The target is the name token of the idea, in the open editor when the target is open.
An imported alias such as `other` reaches the imported idea.
A folder reference has no definition. Its link is the folder-picker command.
A hover renders idea content only when idea_content_tooltip is on.
A request does not wait behind the confirm pass of lazy_features_after_outbound.
The editor calls this request on Ctrl + hover.
The extension does not send the document text from that handler.
The extension does not open a folder picker or a wildcard panel from that handler.
A folder click and a wildcard click use the command document link.
When the engine is node, the provider uses cached Langium ref objects for idea tokens.
It does not scan the document text when the CST already covers the cursor.
Related: editor_reference_activation, wildcard_references_webview.
- implementation
- session.rs, analysis.rs, server.rs, main.ts, register-folder-reference-handling.ts, register-wildcard-reference-handling.ts, reqlan-definition-provider.ts, reqlan-markdown-links.ts
- status
- done
- tests
- session.rs:definition_uses_the_open_neighbor_parse, session.rs:definition_follows_a_changed_neighbor_to_the_name_token, session.rs:definition_of_an_imported_alias_reaches_the_neighbor, session.rs:folder_reference_link_is_a_command, hover_content.rs:hover_shows_idea_content_from_another_file, stdio.rs:stdio_initialize_and_shutdown, editor-link-activation.test.ts:go-to-definition does not send the buffer
reference_resolution_folder
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
If the reference path is a folder, the extension should render a popup with a list of files in that folder.
The link should not try to resolve to a file if it doesn't exist.
The popup is the command document link. Go-to-definition does not open the popup.
Related: editor_reference_activation, reference_goto_definition_speed.
activity_bar_module
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
the extension should provide a activity bar module for the ide.
the activity bar module should display the following information:
- the current file
- the current idea
- ideas referencing the current idea / selection
- a local graph
see activitybar.rq for more details.
reference_code_completion
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
references should code complete the available namespace of ideas
this includes both ideas using hte standards idea namespace syntax, and ideas using file paths, and relative file paths.
Cross-file candidates show import paths and may auto-insert imports:
import_code_completion_rendering
import_code_completion_auto_file_import
Implemented by reqlan-completion-provider.ts.
code_completion
- tests
- completion.test.ts
reference_code_completion_objects
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
reference_code_completion must offer code completion for all valid reqlan references:
- reqlan files ( `.rq` )
- ideas and ideasets in a reqlan file after a quoted path ( `idea` )
- ideasets and ideaset members ( `member` )
- code files
- folders, including folders that do not contain `.rq` files
Import path completion stays limited to `.rq` files.
Anonymous file-reference paths share ranking and alias logic with import paths, but they include every file and folder target.
Scanning every workspace file on each keystroke is too expensive: reference_code_completion_performance.
- implementation
- reqlan-completion-provider.ts, reqlan-completion-context.ts, reqlan-path-completion.ts
- status
- done
- tests
- completion.test.ts:anonymous file references complete code files, folders, and .rq files, completion.test.ts:completes ideas and ideasets after a quoted file path, completion.test.ts:completes ideaset members after a dotted qualifier
reference_code_completion_performance
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
reference_code_completion_objects must stay interactive on large workspaces.
Path completion must not re-walk the filesystem on every keystroke: cache directory listings and reuse them for import and anonymous file-reference completion.
Ranking must precompute proximity keys rather than recomputing hop distance per comparator call.
Idea-graph ranking must reuse per-document adjacency across completion requests while document versions are unchanged.
Anonymous file-reference completion may omit distant candidates after proximity ranking so the list stays bounded.
Implemented by reqlan-path-completion.ts
( `clearPathCompletionCaches`, listing cache, `sortPathCompletionCandidates` ),
reqlan-completion-provider.ts,
and reqlan-completion-context.ts.
reference_code_completion
reference_code_completion_performance
- implementation
- reqlan-path-completion.ts, reqlan-completion-provider.ts, reqlan-completion-context.ts
- status
- done
- tests
- completion.test.ts:anonymous file references complete code files, folders, and .rq files, completion.test.ts:completes ideas and ideasets after a quoted file path, completion.test.ts:completes ideaset members after a dotted qualifier, completion-perf.test.ts, completion-perf.test.ts:cached path completion does not re-read directories, completion-perf.test.ts:large-tree anonymous completion stays under budget
reference_code_completion_sequencing
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
reference_code_completion should be offered, not alphabetically, but by distance, then alphabetically.
Implemented by reqlan-completion-provider.ts.
code_completion
- tests
- completion.test.ts
attribute_code_completion_main_descriptiption
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
the main description attribute is expected to be prose, so, the dropdown shouldn't be rendered in this context.
attribute_code_completion_attribute_key
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
the attribute key should complete based on endorsed keys and what is present in the index
i. e. after the @ symbol at the start of a line, the used attributes should be completed.
subsquently, values of the attribute key should be completed based on the values in that attribute key.
view_references_as_inlay_hints
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
References should be shown as inlay hints in the editor.
This should be a toggleable setting, which should be available in the command palette.
N-lines ( configurable setting ) of hints should be shown below the idea.
Inbound lookup must stay interactive on large graphs via inbound_inlay_index_performance.
The Rust server honours `reqlan.referencesInlayHints.enabled` and the host inbound snapshot ( `byIdeaName` + `fileReferencers` ).
Implemented by reqlan-inlay-hint-provider.ts, reqlan-inbound-reference-inlay-label.ts, reqlan-inlay-hint-settings.ts, register-reference-inlay-hints.ts, and session.rs.
- implementation
- session.rs, server.rs, idea-content-tooltip.ts, register-reference-inlay-hints.ts
- status
- done
- tests
- inlay-hints.test.ts, inbound-referencer-index-perf.test.ts, parity.rs:formats_inbound_referencers_as_an_inlayed_attribute
traceable_inlay_hints
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
A click on one inbound referencer opens that idea via `reqlan.openInboundReferencer` → host openIndexFile ( same path as activity-bar / index opens ).
The inlay label part must not use raw LSP Location for the click gesture — Cursor rejects detached file: / / opens that Location would trigger.
A click on the remainder opens the inbound summary for that idea.
The backlink tooltip uses the shared document-link file URI builder ( encoded path, `#L` fragment ).
The Rust server emits the same markdown tooltip and open command ( language_server_rust ).
A file path with a space opens that file from the inlay click and from the tooltip.
A directory segment " reqlan rq " opens that file.
Implemented by reqlan-inbound-reference-inlay-label.ts, reqlan-inlay-hint-provider.ts, reqlan-inlay-hint-settings.ts, register-reference-inlay-hints.ts, reqlan-file-link-resolver.ts, reqlan-path-resolve.ts, and analysis.rs.
- implementation
- reqlan-inbound-reference-inlay-label.ts, reqlan-inlay-hint-provider.ts, reqlan-inlay-hint-settings.ts, register-reference-inlay-hints.ts, reqlan-file-link-resolver.ts, reqlan-path-resolve.ts, analysis.rs
- status
- done
- tests
- inlay-hints.test.ts, inlay-hints.test.ts:backlink tooltip opens the real file URI when the path has a space, inlay-hints.test.ts:attaches open command to clickable referencer label parts, parity.rs:formats_inbound_referencers_as_an_inlayed_attribute, parity.rs:backlink_inlay_command_and_tooltip_encode_spaces_like_gotos
inbound_inlay_hints_whole_graph
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
Inbound references shown in view_references_as_inlay_hints should include referencers from the whole requirement graph across the workspace, not only ideas declared in the current file.
Coverage comes from SQLite edges_table via unify_inbound_indexes, not from Langium IndexManager.
Whole-graph coverage must not regress to per-idea full-index scans — see inbound_inlay_index_performance.
Implemented by reqlan-inbound-reference-inlay-label.ts, reqlan-inlay-hint-provider.ts.
view_references_as_inlay_hints
traceable_inlay_hints
inbound_inlay_hints_whole_graph
- status
- done
- tests
- inlay-hints.test.ts, inbound-referencer-index-perf.test.ts:inlay referencers come from the pushed snapshot, not findAllReferences
inbound_inlay_index_performance
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
Computing inbound reference inlay hints for a document with many ideas must look up a
pre-pushed SQLite inbound snapshot ( unify_inbound_indexes )
in near-constant time per declaration.
Show the hints when that snapshot arrives
( lazy_features_after_outbound ).
Until the first ready snapshot arrives, hints stay empty.
Later index sync must not clear last-good with an empty mid-sync push
( inbound_snapshot_events ).
Must not call Langium `findAllReferences` / equivalent full-index scans once per idea
( that is O ( ideas × workspace refs ) and freezes the editor on dense graphs ).
Implemented by reqlan-inbound-reference-inlay-label.ts
and reqlan-inlay-hint-provider.ts.
view_references_as_inlay_hints
inbound_inlay_hints_whole_graph
- status
- done
- tests
- inbound-referencer-index-perf.test.ts:inlay referencers come from the pushed snapshot, not findAllReferences, inbound-snapshot-push.test.ts, inbound-snapshot-store.test.ts
code_lens_reference_types
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
References should have a codelens button.
The button should be togleable in settings.
The button should the classification of the reference. e. g. ' open reqlan file', " open { extension } file', ' open folder', ' open idea'
Clicking the CodeLens should open a reference card with summary stats — not navigate, because references already act as editor links.
The card should offer open / reveal / file-selector actions when useful.
Folders should be handled by focusing on the ide explorer, or by opening a file selector.
Some summary stats should be shown for references - e. g. last edited, count of references, count of referencers, etc.
File-top inbound file references are file_inbound_code_lens, not this outbound classification lens.
Implemented by reqlan-code-lens-provider.ts, reqlan-reference-code-lens.ts, reqlan-code-lens-settings.ts, register-reference-code-lens.ts, and reference-code-lens-card.ts.
code_lens_reference_types
- status
- done
- tests
- code-lens.test.ts
file_inbound_code_lens
reqlan rq/extension/language/syntax/features-syntax-highlighting.rq
The editor shows inbound file references in a codelens at the top of the file.
The CodeLens uses the same `@referenced-by: (name, …)` list form as idea inlay hints
( view_references_as_inlay_hints ).
Idea declarations keep `@referenced-by` for idea-to-idea inbound.
The file CodeLens lists ideas that point at this file with a
file_reference ( path-only and path-with-symbol ).
Click the CodeLens to open the inbound referencers summary for this file.
Hide the CodeLens when the file has no inbound file references.
Read referencers from the SQLite inbound snapshot
( unify_inbound_indexes ).
Show the CodeLens when that snapshot arrives
( lazy_features_after_outbound ).
Do not scan Langium IndexManager.
The file CodeLens is independent of the outbound classification toggle on
code_lens_reference_types.
Applies to `.rq` files and to other indexed files that ideas reference.
Implemented by reqlan-code-lens-provider.ts,
reqlan-file-inbound-code-lens.ts,
reqlan-inbound-snapshot.ts,
inbound-file-referencers.ts,
sqlite-store.ts,
inbound-file-snapshot.ts,
register-inbound-sqlite-sync.ts,
register-file-inbound-code-lens.ts,
register-webview.ts,
and reqlan-inlay-hint-settings.ts.
view_references_as_inlay_hints
file_inbound_code_lens
inbound_inlay_index_performance
- status
- done
- tests
- code-lens.test.ts:shows file inbound referenced-by CodeLens at the top of the file, code-lens.test.ts:omits file inbound CodeLens when the snapshot has no file referencers, code-lens.test.ts:truncates file inbound CodeLens names the same way as idea inlays, inbound-file-referencers.test.ts, inbound-file-referencers.test.ts:resolves relative file_reference edges onto the target file, inbound-file-snapshot.test.ts, queries.rs:inbound_for_file_returns_file_reference_targeting_file, queries.rs:inbound_for_file_returns_file_reference_targeting_code_file
syntax_features
reqlan rq/extension/language/syntax/features-syntax.rq
The extension should provide language support for. rq files via the lsp.
Syntax features should cover ideas, ideasets, imports, references, attributes, comments, and lists.
Broken imports and references should be validated and reported in the editor.
Go-to-definition and find-references should work for ideas, imports, and cross-file links.
Find-references is served by language_server_rust ( `textDocument/references` ).
Autoformatting should be supported for. rq files.
- tests
- session.rs:attribute_catalog_completion_and_find_references, session.rs:definition_hover_highlight_and_link
syntax_highlighting
reqlan rq/extension/language/syntax/features-syntax.rq
. rq files should receive full syntax highlighting coverage for all reqlan constructs.
Semantic token highlighting should distinguish ideas, attributes, references, imports, and keywords.
Path + wildcard idea refs ( `*.rq".idea_*` ) must highlight as links / strings — not comment-grey —
see wildcard_reference_highlighting.
Import lines must colour path and keywords after `import` / `from` —
see import_statement_highlighting.
Same-line named braces ( `name {}`, `name {hello}` ) must close in TextMate so later
one-liners stay visible — see same_line_named_block_highlighting.
- status
- done
syntax_hovering
reqlan rq/extension/language/syntax/features-syntax.rq
Hovering on an idea, ideaset, import, or reference should show a text summary of its content and resolved target.
Hovering on a reference should show where it resolves and any declared reference kind.
The styled body hover is idea_content_tooltip.
idea_content_tooltip
reqlan rq/extension/language/syntax/features-syntax.rq
A hover on an idea name or on a reference shows that idea's content.
The tooltip is markdown. It uses a heading, body lines, attributes, lists, and code fences.
A reference in another file shows that file's idea content.
The setting `reqlan.ideaContentTooltip.enabled` controls this hover.
The default is on.
When the setting is off, the hover shows the idea name and the one-line summary.
Related: syntax_hovering language_server_rust
- implementation
- hover_content.rs, analysis.rs, session.rs, server.rs, idea-content-tooltip.ts, main.ts, package.json
- status
- done
- tests
- hover_content.rs:hover_shows_styled_idea_content_by_default, hover_content.rs:hover_omits_idea_content_when_the_setting_is_off, hover_content.rs:hover_shows_idea_content_from_another_file, idea-content-tooltip.test.ts:package.json enables idea content tooltips by default, idea-content-tooltip.test.ts:a missing value stays on
comment_support
reqlan rq/extension/language/syntax/features-syntax.rq
The extension should recognise reqlan references embedded in comments of arbitrary source files.
Comment reference syntax should follow the form rq, then a quoted path, then a dotted idea name in line comments.
Qualified comment paths must resolve import-root aliases such as `@/` the same way imports do — configuration_import_root_alias, comment_reference_import_root_alias.
Comment references in non-. rq files should support syntax highlighting ( resting underline: comment_reference_resting_underline ), hover, and go-to-definition.
Arbitrary file references should be supported from both. rq files and comment references.
- implementation
- register-comment-reference-links.ts, comment-reference-path-context.ts, reqlan-comment-diagnostics.ts, reqlan-path-resolve.ts
- tests
- against the workspace folder for extension comment links, comment-reference-resolution.test.ts:creates a document link for an import-root aliased comment reference
code_completion
reqlan rq/extension/language/syntax/features-syntax.rq
The extension should complete ideas, imports, and paths from the current file path and resolved import config.
- support for references
- support for imports, including import-root alias paths such as `@/` from configuration_import_root_alias and configuration_import_roots
- support for semantic search
- support for graph-proximity based ranking
String and namespace completion should follow the current file path and import roots.
- implementation
- reqlan-completion-provider.ts, reqlan-path-completion.ts
- tests
- completion.test.ts:completes import-root alias paths
refactor_support
reqlan rq/extension/language/syntax/features-syntax.rq
syntactic symbols should be available for renaming, moving, and deleting. the extension should watch for the change.
Detailed behaviour lives in refactor_support.rq.
Implemented by reqlan-rename-provider.ts, reqlan-idea-refactor.ts, and index.ts.
file_references
reqlan rq/extension/language/syntax/features-syntax.rq
A file reference should act as a link in the editor.
If the target file is empty or has a parse error, the link should remain available and clickable, but should show a warning underline.
If the target file is missing, show an error underline and do not create a document link — see file_reference_errors.
Same-file and imported idea bracket references use the same editor activation as file targets.
See editor_reference_activation.
Implemented by reqlan-file-link-resolver.ts, reqlan-document-link-provider.ts, reqlan-definition-provider.ts, and reqlan-validator.ts.
- tests
- linking.test.ts:document links resolve test file references to the matching test, references.test.ts:keeps colons inside the test name suffix, linking.test.ts:classifyReferenceUri treats existing directories as folders, linking.test.ts:folder file references resolve without reading the directory as a file, linking.test.ts:empty file references produce document links and warning diagnostics, linking.test.ts:parse-error file references produce document links and warning diagnostics, linking.test.ts:missing file references do not produce document links, linking.test.ts:same-file idea references produce document links
sensible_alias_support
reqlan rq/extension/language/syntax/features-syntax.rq
if an imported idea shares a name with an idea in the current file:
When the import uses an alias, the base name may be reused locally — see import_tokenisation.
- subreqs
- duplicate_error { should be raised if a local idea or ideaset shares a name with an import binding (unaliased idea name, or the alias when present). @tests ( validating.test.ts:reports duplicate when local idea shares unaliased import binding validating.test.ts:reports duplicate when local idea shares import alias validating.test.ts:reports duplicate when local ideaset shares a local idea name ) }, sensible_graph_resolution { the imported namespace should not be assosciated with the new idea: e.g. ``` from-import an idea as an alias, then declare a local idea with the original name ``` `myidea` in the import statement should not be assosciated with the new `myidea` definition - they're totally different. @tests ( linking.test.ts:import idea reference resolves to imported file when local idea shares name validating.test.ts:allows local idea when import uses an alias ) }
at_sign_in_idea_text_block
reqlan rq/extension/language/syntax/features-syntax.rq
the @ symbol should only indicate an attribute if at the start of a line.
it should be escapeable with a backslash ( although any character would work as the @ would no longer be at the start of the line )
so @ this_is_not_an_attribute
- this_is_an_attribute
- true
code_completion_import_file_paths
reqlan rq/extension/language/syntax/features-syntax.rq
import files should code complete nicely based on the current file's path; and the resolved import config.
it should support normal relative folder paths; and if import-root aliases are configured.
configuration.rq
imports.rq
code_completion
syntax_welcome_demonstration
reqlan rq/extension/language/syntax/features-syntax.rq
the thanks-for-installing.template.rq should feature some of the core syntax features as reference.
codelens
reqlan rq/extension/language/vsc-primitives.rq
Outbound classification CodeLens on references:
code_lens_reference_types.
File-top inbound file-reference CodeLens:
file_inbound_code_lens.
Idea inbound `@referenced-by` remains an inlay:
view_references_as_inlay_hints.
code_completion
reqlan rq/extension/language/vsc-primitives.rq
Editor completion for ideas, imports, and paths. Canonical requirements: code_completion.
inlay_hints
reqlan rq/extension/language/vsc-primitives.rq
Inbound-reference inlay hints. They appear when the inbound snapshot is ready
( lazy_features_after_outbound )
and stay on last-good until the next ready-state incremental push
( inbound_snapshot_events ).
code_actions
reqlan rq/extension/language/vsc-primitives.rq
Language-server code actions for `.rq` files, plus comment-file Quick Fixes for ignore-error:
- Quick fixes for unresolved references ( add import, rewrite qualified ref, search, create file ) — import_error
- Refactor: search / replace or wrap as idea reference — search_code_actions
- Refactor: move or delete an idea declaration — refactor_symbol_move refactor_symbol_delete
- File-level source action: barrel page — barrel_page
- Quick Fix: insert `//rq-ignore-error` before a line with diagnostics — code_actions_ignore_error
- Quick Fix: create a missing local idea below the idea that contains the unresolved reference — create_idea_below_idea_containing_unresolved_reference_under_cursor
The Rust server returns the same set ( language_server_rust ).
Command-backed search / replace and barrel actions omit LSP command arguments so VS Code does not cache disposable delegating ids; the extension resolves the active editor ( or document ) when the command runs.
The same Quick Fix appears once in one request.
Langium appends validation diagnostics when a document already has diagnostics.
The diagnostic list stays when the document state is below Validated.
The document builder removes previous built-in diagnostics before that append.
One linking error gives one Quick Fix after repeated builds.
- implementation
- reqlan-code-action-provider.ts, code_actions.rs, server.rs, session.rs, reqlan-document-builder.ts, register-import-error-commands.ts, main.ts, main.ts, register-idea-refactor-commands.ts, register-barrel-page-command.ts, register-ignore-error-code-actions.ts, reqlan-ignore-error-action.ts, reqlan-create-idea-below.ts
- status
- done
- tests
- code-actions.test.ts, code_actions.rs, code-actions.test.ts:keeps one quick fix set after repeated builds, extension-package.test.ts, barrel-page-apply.test.ts, idea-refactor.test.ts, ignore-error-action.test.ts, ignore-error-code-action.test.ts, code-actions.test.ts:creates the missing idea below the containing idea when only one is unresolved, code-actions.test.ts:offers all or a specific unresolved idea when the caret idea has several
quick_fixes
reqlan rq/extension/language/vsc-primitives.rq
Quick-fix subset of code_actions ( import errors, ignore-error, create-below ).
current_file_pane
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
Primary contextual pane when a. rq file is active. Sub-sections may collapse independently.
scope_pane
reference_lists_pane
parent_nodes_pane
scope_pane
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
Composed context inspector per scope_pane_design.
Built from reqlan_context_model; not a flat file list.
See context_dimensions for workspace, current file, open files, file history, edit history, manual, and git lenses.
Git lens: git_history_lens ( history-first, not staging mirror ).
Legacy file-only fields live in current_file_context / currentFile slice when the current-file lens is expanded.
Implemented by ScopePane.svelte.
git_history_lens
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
Expanded git dimension in scope_pane: focus-centric development history, not a Source Control duplicate.
Layout:
- Header: branch name, HEAD short hash, muted summary ( e. g. " main · 3 commits · 2 authors " ).
- Focus history ( primary ): up to ~ 8 commits touching the focus file / idea line range — relative time, short hash, subject, author.
Prefer `git log -L` for `.rq` ideas; fall back to path log. Non-. rq uses path `--follow`.
- Authors: compact chip row of top authors from that log window.
- Working tree ( secondary, collapsed by default ): dirty staged / unstaged paths for caution / footprint only.
Focus hero: history cue ( last commit age / branch ), not `git: staged|unstaged`.
Fingerprint Git axis and drilldown list commits / authors ( dirty paths secondary ) per fingerprint_axis_drilldown and tooltip_detail.
Aligns with git_context and development_history_signals.
Performance: heavy focus history must not block link open or first context paint —
see link_open_decoupled_from_git and git_focus_cache_by_head.
Implemented by ScopePane.svelte ContextFingerprint.svelte.
- status
- done
reference_lists_pane
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
Actionable inbound and outbound reference lists for the focused idea.
- Inbound: ideas that reference the focus ( edges to the focus ).
- Outbound: ideas and files the focus references ( edges from the focus ).
- Live same-file inbound / outbound from local_symbolic_analysis
merged with indexed refs per local_symbolic_sidebar.
- Group entries by edge kind ( dependency, related to, file ref, incompatible, etc. ) in collapsible sections.
- Show a short snippet or source line explaining why each edge exists where available.
- Text filter scoped to this pane only ( not the full ui-sql layer ).
- " Add to context " pins an idea into context_tray for Copilot / @ reqlan workflows.
- reference_resolution_parity: panel resolution must match the editor file view.
- unresolved_reference_create: unresolved idea targets get a create affordance, not a dead file link.
Implemented by ReferenceListsPane.svelte.
reference_resolution_parity
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
Reference resolution for the activity-bar references pane must use the same shared rules as the editor
( document links / go-to-definition ), not a second ad-hoc classifier.
- Bare namespace-alias bracket refs such as `ActivityBarApp` that open a file in the editor must index as
resolved `file_reference` edges ( import path ), not unresolved idea refs — per import_namespace.
- Quoted file paths and markdown file links use the same file-target treatment as the language file-link resolver
in reqlan-file-link-resolver.ts /
reqlan-namespace-import-links.ts.
- File targets are opened relative to the defining `.rq` file ( same path join as the miniature graph ), not the workspace root.
- If a target resolves in the file view, it must resolve ( and be openable ) in reference_lists_pane.
Implemented by extract.rs,
file-reference-resolve.ts,
ReferenceListsPane.svelte.
- status
- done
- tests
- extract_parity.rs, file-reference-resolve.test.ts, linking.test.ts:does not report linking error for bare namespace alias references
unresolved_reference_create
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
When an outbound reference remains unresolved after shared resolution ( missing idea, not a file / namespace-alias target ):
- Do **not** treat the label as a file path or navigate to a non-existent file.
- Show an unresolved badge and a ** + ** control with tooltip " Create idea ".
- Activating ** + ** opens create-idea ( reuse pallete_function_create_todo when available;
until then, the existing import-error create-file flow prefilled with the reference name and source document ).
Implemented by ReferenceListsPane.svelte and the activity-bar host message handler.
- status
- done
parent_nodes_pane
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
Upstream context for the focused idea.
- Ancestor chain as a breadcrumb with a configurable depth limit ( not only immediate parents ).
- Status rollup for ancestors ( e. g. counts by @ status ).
- " What blocks completion? " surfaces upstream ideas whose @ status is not done or in-progress.
selection_pane
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
When the user selects text spanning one or more `.rq` ideas ( context_selection ).
- List selected ideas with Focus and Pin actions.
- Contributes selection idea ids to context_footprint and may pair with graph_path_walk as path endpoints.
- Hidden when there is no non-empty multi-line selection overlapping ideas.
context_tray
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
A small pinned set of ideas carried across panes for AI context — the manual_context dimension.
- Chips for pinned ideas with remove control.
- " Clear tray " and " Copy tray as markdown " actions.
- Tray contents are included when invoking @ reqlan context or divide-and-conquer flows per divide_and_conquer.
context_panes_loading
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
Ready panes: scope_pane, reference_lists_pane, and parent_nodes_pane show per-request loading and error, distinct from empty.
context_content_styling
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
Pane bodies must not grow unbounded. Nested lists use NestedSection.svelte ( collapse + scroll ) under CollapsiblePane.svelte.
Priority: scope_pane; reference_lists_pane kind groups; also selection / parents.
ScopePane.svelte ReferenceListsPane.svelte
- status
- done
tooltip_detail
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
Scope pane tooltips are detailed enough to explain *what* a meter means and *why it matters*.
- scope_pane widgets ( stability, dependency pulse, timeline, churn, lens chips, footprint line ) expose granular hover copy on the control and its sub-items.
- ContextFingerprint.svelte has an ⓘ info button with semantic scoring help, per-axis hover copy, and fingerprint_axis_drilldown.
- Scoring copy is sourced from context_signals ( `CONTEXT_FINGERPRINT_HELP`, `CONTEXT_FINGERPRINT_AXIS_HELP`, `buildContextFingerprint` ) so UI stays aligned with context_fingerprint and ai_readiness_gauge.
Implemented by ContextFingerprint.svelte ScopePane.svelte.
- status
- done
fingerprint_axis_drilldown
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
Each ContextFingerprint.svelte axis row ( Files, Requirements, History, Architecture, Git, Diagnostics, Coverage ) is clickable.
Clicking a row toggles a compact contributor table below it ( Source, Item, Detail ) listing what filled that axis — e. g. which lenses included a file, which ideas are in the footprint, git focus commits / authors ( dirty paths secondary ), anomalies, or relationship edges.
Table rows open / focus the related idea or file when actionable. Empty axes show a short “ why care / how to fill ” message.
Mirrors the interaction pattern of dependency_pulse_table. Aligns with context_fingerprint and tooltip_detail.
Implemented by ContextFingerprint.svelte ScopePane.svelte.
- status
- done
dependency_pulse_table
reqlan rq/extension/local-context/activitybar-panels/current_context_scope.rq
The focus-hero DependencyPulse.svelte compass ( ↑ parents, → outbound, ← inbound, ↓ dependents, ● centre ) is clickable.
Clicking any arm or the centre toggles a compact reference table below with Dir, Role, Idea, and Status.
Rows open / focus the related idea. Duplicates of always-on inbound / outbound lists are omitted from the hero; the current-file lens still lists them.
Aligns with dependency_pulse.
Implemented by DependencyPulse.svelte ScopePane.svelte.
- status
- done
miniature_graph_pane
reqlan rq/extension/local-context/activitybar-panels/minigraph.rq
A small interactive graph centred on the cursor idea ( or the file's first idea when the caret is outside any block ).
Consumes graph_library with sidebar-appropriate defaults; slices from local_graph_analysis.
- Default depth 1; + / - controls expand or collapse neighbourhood depth without opening Ideas Summary.
- Pan, zoom, and drag per view_controls.
- Labels default to graph_label_auto via shared GraphCyController ( no separate Labels control here; full control lives on graphical_graph ).
- manual_reframe — " Fit to view " in MiniGraphCanvas.svelte; same API as the full graph tab.
- auto_reframe and reframe_animation when the neighbourhood node set changes ( instant first fit, animated afterward ).
- No full layout / physics menus here ( defer to graphical_graph ).
- Single-click a node opens its source; double-click or " Focus " recentres the slice on that idea.
- Edge kinds styled like the full graph ( including dashed file-reference edges ).
- When nodes are truncated per node_truncation, show " + N more " with a control to open the centred slice in Ideas Summary.
- " Open in Graph tab " hands off centerId and query state to ideas-summary-panel.ts.
Mount cytoscape only while this sub-pane is visible per graph_cy_controller.
minigraph_file_reference_links
reqlan rq/extension/local-context/activitybar-panels/minigraph.rq
when the user clicks on a file reference link in the miniature graph, we should open the file in the editor
if the file is defined as relative, it should be opened relative to the defining file, not the workspace root
Fixed in local_graph_analysis: external file nodes now resolve their path against the defining file's folder ( via the edge source id ) when the slice is built, so a workspace-relative path is handed to the editor open action.
- bugfix
- true
- status
- done
minigraph_loading
reqlan rq/extension/local-context/activitybar-panels/minigraph.rq
Graph slice waits stay in miniature_graph_pane, not a second global overlay.
Show per-request loading and error, distinct from empty.
search_pane
reqlan rq/extension/local-context/activitybar-panels/search.rq
Workspace idea search in the activity bar — find rq ideas by name, summary, or tags without leaving the sidebar.
Complements the modal from search_code_actions; this pane stays open for repeated lookups and inserts.
Implemented by SearchPane.svelte under CollapsiblePane.svelte; host wire in activity-bar-webview-provider.ts / activity-bar-messages.ts / app.svelte.ts.
search_pane_query
search_pane_layout
search_pane_results
search_pane_open_live_file
search_pane_load_more
search_pane_file_hits
search_pane_insert_reference
search_add_to_chat
search_pane_advanced
search_pane_empty_query
search_pane_scoped_status
search_progress
search_pane_seed
search_pane_match_highlighting
- status
- done
search_pane_query
reqlan rq/extension/local-context/activitybar-panels/search.rq
search_pane search input posts a debounced host query.
Ranking uses fuzzy_search in the native search module ( `NativeWorkspaceIndex.fuzzySearch` );
separator-insensitive `_` / `-` / `...` / whitespace. File-name hits: search_pane_file_hits / file_search.
Pages: search_pane_load_more / fuzzy_search_pages.
Highlighting stays in the TS `./fuzzy-search` export.
- status
- done
- tests
- fuzzy.rs, workspace-index.test.ts:fuzzySearch ranks from the native index without listing all ideas in JS, app.svelte.ts, fuzzy_search.rs:workspace_index_fuzzy_search_ranks_without_exporting_catalog
search_pane_layout
reqlan rq/extension/local-context/activitybar-panels/search.rq
search_pane results fill the pane body ( 100 % width ) and scroll inside the pane;
do not nest a second capped NestedSection.svelte scroll.
- status
- done
- tests
- SearchPane.svelte
search_pane_results
reqlan rq/extension/local-context/activitybar-panels/search.rq
search_pane results list is paged ( default page size 40 ) with name, path, and one-line summary;
click opens the idea or file ( search_pane_open_live_file ). Exceeded counts and further pages: search_pane_load_more.
File hits: search_pane_file_hits.
- status
- done
search_pane_open_live_file
reqlan rq/extension/local-context/activitybar-panels/search.rq
A click on a search_pane hit must show the live workspace file at that path.
If that file is already open in a workspace tab, focus that tab and move the caret.
Do not open a second read-only tab with stale content ( a detached `file://` copy that Cursor does not sync ).
Keep the click path cheap: no extra index read, no base discovery.
- implementation
- open-index-file.ts, open-index-file-pick.ts
- status
- done
- tests
- open-index-file.test.ts, open-index-file.test.ts:prefers the document whose URI matches the workspace target
search_pane_load_more
reqlan rq/extension/local-context/activitybar-panels/search.rq
When ranked hits exceed the visible page, search_pane shows an exceeded-count label
( `40+ matches`, or `{n}+ matches` after further pages ) instead of a full total,
and a **Show more** control at the bottom of the list that fetches the next page and appends.
A new query resets to the first page. Uses fuzzy_search_pages ( `offset` + `truncated` ).
- implementation
- SearchPane.svelte, app.svelte.ts, activity-bar-webview-provider.ts, activity-bar-messages.ts, search-results-meta.ts, fuzzy.rs
- status
- done
- tests
- search-results-meta.test.ts, fuzzy.rs:pages_ranked_hits_with_offset_and_truncated, workspace-index.test.ts:fuzzySearch returns file-name hits and pages with offset
search_pane_file_hits
reqlan rq/extension/local-context/activitybar-panels/search.rq
search_pane mixes file_search hits ( kind `file` ) into the ranked list with ideas.
Click opens the file at line 0. File hits do not offer Insert ref or Pin ( those are idea actions ).
Empty-state and placeholder copy mention files.
- implementation
- SearchPane.svelte, app.svelte.ts, activity-bar-webview-provider.ts, fuzzy.rs, native-workspace-index.ts
- status
- done
- tests
- fuzzy.rs:ranks_file_name_hits_with_ideas, fuzzy.rs:ranks_file_name_hits_with_ideas, workspace-index.test.ts:fuzzySearch returns file-name hits and pages with offset, search-results-meta.test.ts
search_pane_insert_reference
reqlan rq/extension/local-context/activitybar-panels/search.rq
Each search_pane hit has an **Insert reference** button that inserts `idea_name` at the
active editor cursor ( or replaces the selection ) via insert-idea-reference.ts, adding an import
when the target is in another file — same rules as search_code_actions.
Helpers: insert-idea-reference-helpers.ts.
- status
- done
search_pane_advanced
reqlan rq/extension/local-context/activitybar-panels/search.rq
search_pane header link **Advanced** opens ideas_list with the current query prefilled.
- status
- done
search_pane_empty_query
reqlan rq/extension/local-context/activitybar-panels/search.rq
Empty query in search_pane: prompt to type ideas or files ( do not dump the full catalog into the pane ).
- status
- done
search_pane_scoped_status
reqlan rq/extension/local-context/activitybar-panels/search.rq
search_pane soft-waits when the index is not ready; scoped errors stay in the pane.
Loading UX: search_progress.
- status
- done
search_pane_seed
reqlan rq/extension/local-context/activitybar-panels/search.rq
Host may seed search_pane via `focusIdeaSearch` ( query + optional pathFilter ) from the
wildcard-matches webview **Open in Search** action
( wildcard_references_webview ).
Path filter is a hard AND after ranking ( idea_path_filter ).
- status
- done
search_pane_match_highlighting
reqlan rq/extension/local-context/activitybar-panels/search.rq
The search_pane_results list highlights the parts of name, path, and summary that matched the query
via SearchHighlight.svelte.
Resilient to fuzzy_search / fuzzy_search_whitespace: contiguous and
separator-insensitive spans, token prefixes / part matches, reordered words, and character-subsequence
( fuzzy / acronym ) marks on short fields such as the idea name — not scattered letters in long summaries.
- implementation
- fuzzy-search.ts, SearchHighlight.svelte, SearchPane.svelte, app.svelte.ts
- status
- done
search_add_to_chat
reqlan rq/extension/local-context/activitybar-panels/search.rq
From each search_pane hit, a split **Add to chat** control:
- Primary button: place compact `#requirement` context into the **current** chat input without submitting.
- ▾ menu ( visible secondary affordance ): **Add to current chat** or **Add to new chat** ( new session, then seed the same payload ).
Tooltips name both behaviours; secondary is not right-click-only.
Same payload shape as add_to_chat ( idea name, path: line, summary ) via open-chat.ts.
Host: open-chat.ts with `{ query, isPartialQuery: true, target: 'current' | 'new' }`.
Cursor note: do not use `workbench.action.chat.open` for **current** ( it always opens a new tab ); see add_to_chat / open-chat.ts.
Clipboard fallback when no chat command is available ( same spirit as add_to_chat ).
Wire: AddToChatButton.svelte / SearchPane.svelte → app.svelte.ts `addToChat(hit, target)` → activity-bar-messages.ts → activity-bar-webview-provider.ts → open-chat.ts.
- implementation
- AddToChatButton.svelte, SearchPane.svelte, app.svelte.ts, activity-bar-messages.ts, activity-bar-webview-provider.ts, open-chat.ts
- status
- done
search_progress
reqlan rq/extension/local-context/activitybar-panels/search.rq
Activity-bar search ranks in the native fuzzy_search module ( rusqlite read + score in-process ).
The host must not hydrate a JS idea catalog or worker before scoring — return only the capped hit list.
A static " Searching … " / " Loading … " label must not be the only signal: the pane should show **live progress** so a slow wait reads as working, not hung.
- Host posts progress for the in-flight search request while native scoring runs ( `Scoring ideas…` ).
- SearchPane.svelte displays the phase label with a continuous activity affordance ( spinner / indeterminate bar ) and elapsed time while loading, for both the empty initial wait and the " Updating … " refresh path.
- Stale progress from superseded queries must not overwrite a newer request; clear progress when results or a scoped error arrive.
- status
- done
- tests
- SearchPane.svelte, app.svelte.ts, activity-bar-webview-provider.ts, activity-bar-messages.ts, workspace-index.test.ts:fuzzySearch ranks from the native index without listing all ideas in JS
todo_pane
reqlan rq/extension/local-context/activitybar-panels/todo.rq
Workspace todo list in the activity bar — ideas that carry the `@todo` special attribute ( special_attributes ), not ideas whose `@status` happens to be `todo`.
Complements the planned Overview todos rollup in overview_page; this pane stays open for quick triage beside the editor.
Layout matches search_pane_layout: flat list in the pane body, not a nested boxed subsection.
- List ideas in the active base where the `todo` attribute is present ( bare `@todo` / flag, or `@todo` with a note ).
- Each row: idea name, source path, and the todo note when present ( omit empty / bare-true values ).
- Click opens the idea in the editor ( same navigation as search_pane_results ).
- Results fill the pane body ( 100 % width ) and scroll inside the pane; do not nest a second capped NestedSection scroll.
- List capped ( default ~ 40 ) with a “ showing N of M ” meta line when truncated; do not dump unbounded index results into the pane.
- Soft-wait when the index is not ready; scoped errors stay in the pane.
- Pane header **Refresh** reloads the list; also reload on index health / sync completion for the active base.
- Optional affordance to create a stub via pallete_function_create_todo when that command ships — do not block the list on it.
Host query + wire: activity-bar-webview-provider.ts / activity-bar-data-service.ts / activity-bar-messages.ts / app.svelte.ts; store query sqlite-store.ts.
Implemented by TodoPane.svelte under CollapsiblePane.svelte; same scroll / fill pattern as SearchPane.svelte.
- status
- done
workspace_pane
reqlan rq/extension/local-context/activitybar-panels/workspace.rq
Multi-base index health, errors, and activity — without duplicating the full Index tab in index_panel.
- workspace_base_picker: choose the active base; do not render a full always-visible base list.
- For the selected base: state badge, sync progress ( processed / total + current file ), idea / edge counts, global and per-file errors, recent activity.
- Clickable file issue list opens the source location in the editor.
- Refresh / cancel in-flight sync / clear & rebuild for the selected base ( or all ); " Open index tab " hands off to ideas-summary-panel.ts with that base selected.
- When no bases exist: empty state with Create Base CTA ( create_base_onboarding ).
Non-blocking sync UX: nonblocking_index.
Implemented by WorkspacePane.svelte.
workspace_base_picker
reqlan rq/extension/local-context/activitybar-panels/workspace.rq
Bases in the Workspace pane are chosen via a **searchable dropdown**, not a stacked list of base rows.
- Closed: shows the active base label ( and compact ready / issue hint when useful ).
- Open: type-to-filter over discovered bases by label and path; selecting a match **pins** the active base ( active_base_switch ) — a pointer swap, not a sync.
- Options surface label / path plus ready state and idea / edge / issue counts so the user can distinguish bases before committing.
- Single-base workspaces still use the same control ( no special flat list ); empty discovery stays on the Create Base CTA.
- Prefer VS Code dropdown tokens for chrome; keep the control compact so health / stats / actions remain the focus of the pane.
Switch UX:
- Selecting a base posts immediately; the picker may flash **Switching … ** until `indexHealth` confirms `activeBaseId` ( should be near-instant ).
- Never kick soft / hard sync on switch; readiness / progress for a not-yet-ready base is whatever the index already reports.
- Editor-follow must not overwrite a user-selected base on the same refresh that applies the selection.
Implemented by BasePicker.svelte in WorkspacePane.svelte; filter helpers in filter-bases.ts.
- status
- done
workspace_loading
reqlan rq/extension/local-context/activitybar-panels/workspace.rq
Index sync progress belongs in workspace_pane; do not treat " index not ready " as a hard global error during cold start.
Host posts index health on view resolve and on `ready`; soft-waits when the index is not ready instead of erroring the whole bar.
Waiting for index: use workspace_pane sync progress affordance.
When the status line *is* in error, show it prominently per error_status_bar.
workspace_content_styling
reqlan rq/extension/local-context/activitybar-panels/workspace.rq
Pane bodies must not grow unbounded. Nested lists use NestedSection.svelte ( collapse + scroll ) under CollapsiblePane.svelte.
File → errors grouping via group-file-issues.ts in WorkspacePane.svelte.
- status
- done
local_graph_view
reqlan rq/extension/local-context/activitybar.rq
The activity bar provides a local graph view scoped to the current file or selected idea.
The local graph should show direct and optionally indirect references with a configurable depth.
activity_bar
reqlan rq/extension/local-context/activitybar.rq
The extension should provide an activity bar sidebar for editor-adjacent requirement context per local_graph_view.
UI is implemented as Svelte webview panes per core.rq, not as a long-lived tree of static rows.
The host loads slices from the index via local_graph_analysis and forwards editor focus through activity-bar-webview-provider.ts and activity-bar-data-service.ts.
Panes should be performance conscious: capped neighbourhoods, lazy cytoscape mount, debounced cursor updates — same discipline as webview.
Workspace-wide tables, full layout controls, and unconstrained graph dumps belong in Ideas Summary per ideas_summary; panes link out with prefilled state instead of duplicating those views.
activity_bar_styling
reqlan rq/extension/local-context/activitybar.rq
Activity bar chrome for the panes stack under App.svelte / CollapsiblePane.svelte.
- **Open panes fill** the remaining bar height ( flex grow ); collapsed panes stay header-sized. A single open pane takes the full stack; multiple open panes share space by persisted relative weights.
- Each expanded pane is **resizable** when more than one is open ( drag handle adjusts weight ); heights / weights persist with expand state via App.svelte view state.
- The bar itself **scrolls** when minimum pane sizes exceed the webview viewport; otherwise pane bodies scroll internally.
- Pane shells **persist** across bootstrap / empty / invalid states — hide or soften **content** inside the pane ( e. g. SelectionPane.svelte empty copy ), do not unmount the section for phase or missing data. Bootstrap banner remains per loading_state; list overflow still uses panel_content_styling / NestedSection.svelte.
Layout helpers: pane-layout.ts.
- status
- done
icon
reqlan rq/extension/local-context/activitybar.rq
the activity bar icon should use the reqlan logo. brand.rq
panes
reqlan rq/extension/local-context/activitybar.rq
- header_buttons
- workspace_pane
- search_pane
- todo_pane
- current_file_pane
- selection_pane
- ideaset_pane
- file_references_pane
- recent_pane
header_buttons
reqlan rq/extension/local-context/activitybar.rq
Cross-pane controls live in a compact header above the pane stack.
- " Sync with editor " toggle: panes follow the active editor and cursor by default; when off, stay pinned on the last focused idea.
- hop_depth_control: global graph hop depth for context search, graph slice, references, and ancestors — not a boolean toggle.
- " Open in Ideas Summary ": reveal ideas-summary-panel.ts with the ideas table filtered to the current file, or the graph tab centred on the current idea.
- " Export slice ": JSON or CSV of the current neighbourhood only. This slice is lighter than workspace export.rq".export_JSON and export.rq".export_csv.
- " Copy as markdown ": copy the focused idea plus parents and reference lists for pasting into chat or PRs.
- Refresh control tied to index readiness.
- info_site_link
- Status / error line under the toolbar: error_status_bar
error_status_bar
reqlan rq/extension/local-context/activitybar.rq
When the activity bar status line ( HeaderBar.svelte ) or Ideas Summary status chrome
( StatusBar.svelte )
is in an error state ( `statusError` ), surface the error **prominently** — do not mute it or bury it behind healthy index counts.
- Lead the status text with the error summary or issue count; healthy idea / reference counts may follow as secondary context.
- Use error foreground, error validation background, a distinct error label, and `role="alert"` so the message is visually and accessibly distinct from idle status.
- Bootstrap error banner ( BootstrapStatus.svelte in loading_state ) must not apply muted styling to the error detail.
Soft-waits for an unready index stay non-error per error_status_bar / workspace_loading; this idea covers true error states only.
Shared copy helper: index-status-text.ts.
- implementation
- HeaderBar.svelte, BootstrapStatus.svelte, global.css, app.svelte.ts, StatusBar.svelte, global.css, index-status-text.ts
- status
- done
hop_depth_control
reqlan rq/extension/local-context/activitybar.rq
A **- / value / + ** button pair ( not a 1 - hop / 2 - hop toggle ) sets global_hop_depth.
- Minimum hop depth is 1 ( direct neighbours only ); **-** is disabled at minimum.
- Maximum hop depth is capped ( default 4 for the activity bar ); ** + ** is disabled at maximum.
- Changing global depth rebuilds reqlan_context_model, refreshes graph / refs / ancestors panes, and updates context_footprint.
- When context_footprint has no centre, depth still updates session state. Panes refresh when a centre appears.
- Legacy `setIncludeIndirect` maps to depth 2 / 1 for backward compatibility during migration.
info_site_link
reqlan rq/extension/local-context/activitybar.rq
The header shows an info control that opens the project site in the system browser.
Link id `site` from phonebook per activity_bar_site_link.
Resolved in the extension host via phonebook.ts ( canonical data in phonebook.json ), not hardcoded in the webview.
The webview receives the resolved label and href from activity-bar-webview-provider.ts and posts `openPhonebookLink` when the user activates the control.
scope_pane
reqlan rq/extension/local-context/activitybar.rq
Composed context inspector — details in scope_pane.
git_history_lens
reqlan rq/extension/local-context/activitybar.rq
Focus-centric git history in the git lens — details in git_history_lens.
miniature_graph_pane
reqlan rq/extension/local-context/activitybar.rq
Small interactive neighbourhood graph — details in miniature_graph_pane.
reference_lists_pane
reqlan rq/extension/local-context/activitybar.rq
Inbound / outbound reference lists — details in reference_lists_pane.
Shared editor / panel resolution: reference_resolution_parity.
Unresolved idea create affordance: unresolved_reference_create.
refernce_lists_pane_reference_tiering
reqlan rq/extension/local-context/activitybar.rq
Inbound refernces may be direct, or via ideaset references.
The reference_lists_pane should tier the references based on the reference type. Design must keep in mind that that the ideaset refernces are likely more numerous and lower signal.
- todo
- true
parent_nodes_pane
reqlan rq/extension/local-context/activitybar.rq
Upstream ancestor chain — details in parent_nodes_pane.
selection_pane
reqlan rq/extension/local-context/activitybar.rq
Multi-idea selection list — details in selection_pane.
ideaset_pane
reqlan rq/extension/local-context/activitybar.rq
When the focused idea belongs to one or more ideasets.
- List ideaset names with a dropdown of member chips ( same interaction model as idea_sets_tab ).
- Path column links to the ideaset source file.
- Hidden when the focus idea is not a member of any ideaset.
file_references_pane
reqlan rq/extension/local-context/activitybar.rq
File-scoped edges only — inbound and outbound file references for the focused idea.
Useful for tracing which source files implement or mention a requirement.
- Group shared file targets per referenced_files_grouping when multiple ideas reference the same path.
- Line-qualified references should navigate to the specific line when present.
recent_pane
reqlan rq/extension/local-context/activitybar.rq
Recently touched ideas in the session ( configurable count and truncation basis per node_truncation ).
- Click opens the idea; optional pin to context_tray.
context_tray
reqlan rq/extension/local-context/activitybar.rq
Pinned ideas for AI context — details in context_tray.
performance
reqlan rq/extension/local-context/activitybar.rq
Sidebar webviews share the same constraints as webview_threading.
- The HTML / Svelte shell paints before index discovery begins; the post-paint `ready` handshake starts indexing.
- Require the host-matching core engine at activate; do not embed a sql. js vendor in the activation-critical host bundle.
- Default neighbourhood slices; never load the full workspace graph into a pane.
- Debounce editor selection and cursor events before rebuilding slices.
- Lazy-mount cytoscape only for visible sub-panes; destroy when collapsed or hidden.
- Reuse local_graph_analysis and graph query builders rather than ad-hoc index walks in the webview.
- Interactive actions ( `openIdea`, insert ref, add to chat, phonebook / Ideas Summary links ) are handled on a priority path: they cancel in-flight search / refresh work and briefly quiet editor-driven rebuilds so subsequent clicks stay snappy.
- Idea search scoring runs in a worker thread with a preloaded catalog; catalog load yields so it cannot monopolize the host.
- Link navigation must stay snappy once a target is already resolved: link_open_decoupled_from_git, link_open_interactive_quiet, lean_resolved_open, git_focus_cache_by_head.
- status
- done
link_open_decoupled_from_git
reqlan rq/extension/local-context/activitybar.rq
Opening a resolved idea / file link must not await git focus history or idea-at-revision parsing.
Host posts index-backed context ( scope, references, graph, ancestors ) first; git_history_lens
enrichment runs asynchronously afterward and may re-post context when ready.
Light git chrome ( branch / dirty from the VS Code git API ) may ride along with the first paint; `git log -L`,
`git show` + Langium parse-at-revision, and focus stats must not block open or the first context post.
Implemented by activity-bar-webview-provider.ts
and git-context.ts.
- status
- done
link_open_interactive_quiet
reqlan rq/extension/local-context/activitybar.rq
Programmatic and editor file-switch navigation share the interactive quiet path with webview `openIdea`:
cancel in-flight search / refresh and briefly suppress editor-driven pane rebuilds so the open settles
before context rebuild. Selection moves within the same document keep the short debounce only
( no full interactive cancel ). Document-link / go-to-definition opens that change the active file
are covered by active-editor-switch quieting.
Implemented by activity-bar-webview-provider.ts.
- status
- done
lean_resolved_open
reqlan rq/extension/local-context/activitybar.rq
When a link already carries a resolved `fileUri` / `targetPath`, open that URI at the given line —
do not re-classify resolution or walk base discovery on the click path.
Pass the active base root into open-index-file.ts
so resolve-index-file-uri.ts skips tree discovery.
`toIndexFileUri` fallbacks ( editor selection, git chrome, open-tab scan ) must use
base-discovery.ts".nearestBaseRoot ( ancestor `.reqlan` walk ),
never `discoverBases` ( full workspace scan ). Clicking a search hit that already has `fileUri` + line
must not wait on catalog scoring or base rediscovery.
- status
- done
- tests
- open-index-file.ts, resolve-index-file-uri.ts, activity-bar-webview-provider.ts, base-discovery.ts, base-discovery.test.ts, base-discovery.test.ts:nearestBaseRoot walks ancestors instead of scanning sibling trees
git_focus_cache_by_head
reqlan rq/extension/local-context/activitybar.rq
Focus git history / stats caches are not TTL-evicted on a fixed wall-clock window.
Refresh a cache entry only when its write timestamp is **before** the repository's latest commit
authored time ( HEAD ); while `cache.at >= latestCommitAuthoredAt`, reuse the entry.
Applies to focus history, focus stats, and range-commit count caches in
git-context.ts.
Related UX: git_history_lens.
- status
- done
implementation_priority
reqlan rq/extension/local-context/activitybar.rq
Suggested build order:
1. scope_pane and reference_lists_pane ( index data only, no cytoscape ).
2. miniature_graph_pane with expand / collapse and handoff to Ideas Summary.
3. parent_nodes_pane with status rollup.
4. context_tray and create-stub integration with pallete_function_create_todo.
5. selection_pane, ideaset_pane, file_references_pane, recent_pane.
component_list
reqlan rq/extension/local-context/activitybar.rq
Priority release ( shipped ):
- Shell: App.svelte, HeaderBar ( includes info_site_link ), CollapsiblePane in activity-bar
- Panes: WorkspacePane, SearchPane.svelte, TodoPane.svelte, ScopePane, SelectionPane, ReferenceListsPane, MiniatureGraphPane, ParentNodesPane, ContextTray
- Graph: MiniGraphCanvas.svelte consuming shared graph lib per graph.rq
- Host: activity-bar-webview-provider.ts, activity-bar-data-service.ts, wire types in activity-bar-messages.ts
- HTML: get-activity-bar-html.ts
- Build: vite.config.ts → media / webviews / activity-bar /
Deferred ( not in priority release ):
- IdeasetPane, FileReferencesPane, RecentPane
- graph_path_walk UI pane
- ExportSliceButton
- Full workspace export via export.rq".export_JSON and export.rq".export_csv
minigraph_file_reference_links
reqlan rq/extension/local-context/activitybar.rq
File-ref click open behaviour — details in minigraph_file_reference_links.
- bugfix
- true
- status
- done
loading_state
reqlan rq/extension/local-context/activitybar.rq
After the activity bar shell mounts, the header may appear before pane data.
Cover every sequencing beat with an explicit loading or error affordance — never a blank content area:
1. HTML shell ( before Svelte boots ): inline waiting markup in get-activity-bar-html.ts.
2. Connecting: header visible; a post-first-frame `ready` handshake starts the index and requests the first host state.
3. Waiting for index: workspace_loading.
4. Ready panes: context_panes_loading, minigraph_loading, and search_progress.
Index sync progress belongs in workspace_pane; graph slice waits stay in miniature_graph_pane; idea-search phases stay in search_pane — not a second global overlay.
Host posts index health on `ready` and on subsequent status changes; soft-waits when the index is not ready instead of erroring the whole bar.
Pane shells stay mounted through these phases per activity_bar_styling; only content / bootstrap banner reflect invalid or loading states.
True error states ( status line + bootstrap banner ) must show the error prominently per error_status_bar.
- status
- done
panel_content_styling
reqlan rq/extension/local-context/activitybar.rq
Pane bodies must not grow unbounded. Nested lists use NestedSection.svelte ( collapse + scroll ) under CollapsiblePane.svelte.
Shell resize / fill / scroll behaviour: activity_bar_styling.
Details: workspace_content_styling, context_content_styling.
WorkspacePane.svelte ScopePane.svelte ReferenceListsPane.svelte
- status
- done
context_scope_v2
reqlan rq/extension/local-context/context-scope-v2.rq
Evolves context_scope from a **source-oriented** model
( " where did this context come from? " ) to a **decision-oriented** model
( " what information helps a human or AI make the next decision? " ).
v1 context_dimensions remain valid *producers*
( workspace, current file, open files, file history, edit history, manual, git ).
v2 separates those producers from extracted signals, synthesized knowledge,
presentation views, and consumers — so new analyses can be added without
inventing new dimensions each time.
Primary UI principle: show_dont_tell — make project health, momentum,
relationships, and intent legible at a glance. Host fact chips
( " 17 modified files " ) remain useful; widgets below are the preferred
default for conveying meaning.
Surfaces: extend scope_pane / scope_pane_design,
Ideas Summary ( ideas_summary ), and graph overlays
( graphical_graph ) — same signals, different projections.
- status
- in-progress
context_model_layers
reqlan rq/extension/local-context/context-scope-v2.rq
Canonical v2 layers. Implementation builds on
reqlan_context_model; consumers must not reconstruct
project understanding independently.
- context_model
- sources — context_sources
signals — context_signals
synthesis — synthesized_context
views — context_views
consumers — context_consumers - status
- done
context_sources
reqlan rq/extension/local-context/context-scope-v2.rq
Stable raw producers. Answer: " Where are we collecting information from? "
Map from v1: workspace_context,
current_file_context, open_files_context,
file_history_context, edit_history_context,
manual_context, git_context become
sources ( and contributions ), not the whole model.
`workspace` = VS Code workspace chrome / ambient multi-base glance ( folder roots, discovery empty state ).
`base` = the active ontology base ( `.reqlan` - marked container ): its index, readiness, and path ( implied_context ).
Requirements graph and project index bind to the active base's store, not a merged workspace graph.
- items
- workspace, base, active_file, editor_state, selection, manual, git_repository, requirements_graph, project_index, language_server, build_system, diagnostics, tasks, terminal, external_tools
- status
- incomplete
base_signals
reqlan rq/extension/local-context/context-scope-v2.rq
Multi-base facts for context_signals / synthesized_context:
active_base_id, active_base_root, active_base_ready, idea / edge counts for the active base,
sibling_bases ( id, path, ready, counts ), discovery_empty ( prompt create-base ).
Consumed by workspace_pane, Ideas Summary base switcher, and project_weather.
- status
- in-progress
context_signals
reqlan rq/extension/local-context/context-scope-v2.rq
Extracted facts. Answer: " What useful information exists? "
One source may emit many signals ( e. g. git → development history, not only staged / unstaged ).
Families:
- requirement_signals
- file_signals
- development_history_signals
- project_activity_signals
- semantic_signals
- quality_signals
- user_signals
- relationship_signals
- temporal_signals
- risk_signals
- architecture_signals
- requirement_lifecycle_signals
- base_signals
Signals are evidence; synthesized_context merges them into actionable knowledge.
- status
- done
requirement_signals
reqlan rq/extension/local-context/context-scope-v2.rq
related_requirements, parents, children, incoming / outgoing references,
linked implementation files, coverage status, requirement age, stability,
priority, verification state, orphaned, cycles, missing references.
file_signals
reqlan rq/extension/local-context/context-scope-v2.rq
active file, related files, recently viewed, recently edited, high churn,
frequently opened, ownership, generated / test / implementation /
specification / documentation classification.
development_history_signals
reqlan rq/extension/local-context/context-scope-v2.rq
Prefer actionable history over staged / unstaged alone.
development_context ( git reimagined ): current branch, active issue,
release version, commits, authors, change frequency / velocity, historical
and semantic hotspots, last meaningful modification, first introduction,
ownership concentration, refactor / merge likelihood, stability score.
First UI consumer beyond create / modify dates: git_context
/ git_history_lens —
focus commit trail and authors; working-tree staging demoted to secondary.
- development_history
- creation_date, last_modified, edit_frequency, authors, commit_count,
time_since_touched, active_development, historical_hotspot,
first_introduced, last_semantic_change, last_structural_change
project_activity_signals
reqlan rq/extension/local-context/context-scope-v2.rq
currently changing subsystem, hot / cold modules, high activity area,
merge conflicts nearby, active branch, recent issue cluster,
recent requirement churn, release / milestone affected.
semantic_signals
reqlan rq/extension/local-context/context-scope-v2.rq
concept clusters, shared vocabulary, duplicate / near-duplicate /
similar requirements, contradictions, implicit dependencies,
missing abstraction, large / isolated concepts.
quality_signals
reqlan rq/extension/local-context/context-scope-v2.rq
missing documentation, large files / requirements, broken references,
failing diagnostics, lint / parse / test / build failures, coverage gaps.
user_signals
reqlan rq/extension/local-context/context-scope-v2.rq
manual pins, recent focus, navigation history, editing intent,
copied context, AI conversation history, last searched,
last graph traversal, frequently revisited.
relationship_signals
reqlan rq/extension/local-context/context-scope-v2.rq
—
- relationship_context
- strongest_neighbours, most/least referenced,
growing/shrinking dependencies, new/removed links,
unstable neighbours, implementation distance, test distance
temporal_signals
reqlan rq/extension/local-context/context-scope-v2.rq
Enables queries: what changed this week, why this requirement changed,
newly introduced risks, recent architectural evolution.
- temporal_context
- recent, today, this_week, this_sprint, this_release,
historical, archived, obsolete, experimental
risk_signals
reqlan rq/extension/local-context/context-scope-v2.rq
—
- risk_context
- high_churn, many_dependents, poor_documentation, large_implementation,
high_complexity, missing_tests, recent_regressions, many_open_issues,
ownership_risk, single_contributor, breaking_history, high_review_latency
architecture_signals
reqlan rq/extension/local-context/context-scope-v2.rq
—
- architecture_context
- subsystem, bounded_context, layer, module, feature, package,
service, deployment, ownership, technology_stack
requirement_lifecycle_signals
reqlan rq/extension/local-context/context-scope-v2.rq
—
- requirement_history
- created, first_implemented, first_referenced, last_edited,
last_reviewed, last_tested, last_verified, revision_count,
breaking / major / minor revisions, active_duration, inactive_duration
synthesized_context
reqlan rq/extension/local-context/context-scope-v2.rq
Signals merged into decision-oriented knowledge not tied to a single source.
Example projection on a requirement:
- Importance, Confidence, Stability, Recent Activity
- Dependencies, Implementations, Tests, Documentation
- AI Risk
Synthesis powers show_dont_tell widgets and
ai_integration exports — preference for compact synthesized
facts over raw dimension dumps ( ai_context_export ).
- status
- done
context_views
reqlan rq/extension/local-context/context-scope-v2.rq
Projections over the same signals — not separate data models.
Timeline · Graph · File · Requirement · Subsystem · Concept ·
Implementation · History · Risk · AI Summary.
- status
- incomplete
context_consumers
reqlan rq/extension/local-context/context-scope-v2.rq
Shared semantic representation for: UI widgets, graph traversal,
AI agents, search, diagnostics, navigation-by-intent.
New analyses register as signal producers; consumers bind to signals /
synthesis, not to ad-hoc dimension lists.
- status
- incomplete
show_dont_tell
reqlan rq/extension/local-context/context-scope-v2.rq
Make project state **legible at a glance**. Prefer visual evidence of
health, momentum, relationships, and intent over numeric fact lists.
Widgets below are show-don ' t-tell components for context_scope_v2;
each consumes context_signals / synthesized_context and may appear
in activity bar, Ideas Summary, focus heroes, search results, or graph overlays.
Placement guidance:
- Focus / card density: timeline_ribbon, churn_heat_bar, dependency_pulse,
stability_meter, change_velocity, requirement_lifecycle_wheel,
requirement_card, confidence_card, ai_readiness_gauge
- Workspace chrome / dashboard denser: activity_river, project_weather,
context_fingerprint, architectural_map
- Graph / Ideas Summary: hotspot_overlay, impact_radius,
activity_constellation, historical_replay_slider, relationship_cloud
- Coverage / ownership / density: knowledge_coverage, traceability_matrix,
ownership_distribution, concept_density, context_radar, semantic_diff_viewer
- status
- in-progress
timeline_ribbon
reqlan rq/extension/local-context/context-scope-v2.rq
Horizontal lifecycle ribbon for a requirement ( or focused entity ), not a single " last modified " label.
Show milestones along a line toward Now — e. g. created, first implementation,
last reviewed, current edit, last test — so maturity and recent activity
are visible in one glance.
Consumes requirement_lifecycle_signals and temporal_signals.
Fits scope_pane_design. focus_hero and requirement_card.
- status
- incomplete
churn_heat_bar
reqlan rq/extension/local-context/context-scope-v2.rq
Compact sparkline of edit intensity over time for a requirement, file,
folder, or subsystem ( e. g. ▁ ▁ ▂ ▁ ▁ ▇ █ ▆ ▂ ▁ ▁ ).
Hover reveals synthesized story ( stable / large rewrite / quiet since ).
Consumes development_history_signals and project_activity_signals.
- status
- incomplete
dependency_pulse
reqlan rq/extension/local-context/context-scope-v2.rq
Spatial dependency summary instead of " Parents: 4 / Children: 12 ".
Compact compass ( ↑ parents, → children, ← siblings, ↓ dependents ) and / or
a filled **Dependency Load** bar showing centrality growth.
Consumes requirement_signals and relationship_signals.
Surfaced on focus hero and graph node details.
Click any arm or the centre toggles a reference table below the compass
( Dir / Role / Idea / Status ) per dependency_pulse_table.
- status
- incomplete
stability_meter
reqlan rq/extension/local-context/context-scope-v2.rq
Segmented meter + percent ( e. g. Stable █ █ █ █ █ █ █ █ █ ░ 91 % ) derived from
edit frequency, age, dependency churn, and issue count — not raw git status.
AI and humans use it as a confidence cue for change. Pair with
confidence_card and risk_signals.
- status
- incomplete
confidence_card
reqlan rq/extension/local-context/context-scope-v2.rq
Pre-edit checklist card: High / Medium / Low confidence with check / warn rows
( stable, reviewed, tested, high fanout, … ) and a confidence %.
Shown before AI modify workflows ( ai_integration ) and on
focus when synthesis is available.
- status
- incomplete
activity_river
reqlan rq/extension/local-context/context-scope-v2.rq
Workspace-top ribbon of recent activity density ( yesterday / today bursts ).
Shows momentum, not a file list. Consumes project_activity_signals
and user_signals.
- status
- incomplete
architectural_map
reqlan rq/extension/local-context/context-scope-v2.rq
Tiny layered minimap ( UI / Services / Core / Infra … ) with current focus
highlighted and bar width for effort concentration.
Consumes architecture_signals and project_activity_signals.
Links out to Ideas Summary graph rather than duplicating full layout.
- status
- incomplete
hotspot_overlay
reqlan rq/extension/local-context/context-scope-v2.rq
Graph-node encoding of churn / risk / discussion / instability
( size rings ○ ◎ ⬤ or green → red ). Same signal set as activity_constellation.
Applies to miniature_graph_pane and
graphical_graph.
- status
- incomplete
requirement_lifecycle_wheel
reqlan rq/extension/local-context/context-scope-v2.rq
Four-quadrant wheel: Specify · Implement · Test · Review.
Segments fill as evidence accumulates from requirement_lifecycle_signals
and quality_signals. Compact lifecycle for engineering projects.
- status
- incomplete
change_velocity
reqlan rq/extension/local-context/context-scope-v2.rq
Slow ↔ Fast bar from edits / week ( or equivalent ). Complements churn_heat_bar
( shape over time ) with a single magnitude readout.
- status
- incomplete
concept_density
reqlan rq/extension/local-context/context-scope-v2.rq
Per-folder or per-subsystem bars of conceptual richness
( Authentication █ █ █ █ █ █ █ █ █ █ vs Payments █ █ █ ).
Consumes semantic_signals; useful in Ideas Summary folders / index panel.
- status
- incomplete
knowledge_coverage
reqlan rq/extension/local-context/context-scope-v2.rq
Stacked coverage bars: Requirements / Implementation / Tests / Docs —
prefer filled bars over bare percentages. Consumes quality_signals
and requirement_signals. Pair with traceability_matrix.
- status
- incomplete
traceability_matrix
reqlan rq/extension/local-context/context-scope-v2.rq
Compact Req × Impl × Test ( and optional Docs ) check matrix for a local
neighbourhood or subsystem. Exposes gaps immediately.
Neighbourhood-scoped only — full-workspace matrices stay in Ideas Summary
with pagination / filters per ideas_summary.
- status
- incomplete
relationship_cloud
reqlan rq/extension/local-context/context-scope-v2.rq
Compact spatial alternative to a full graph: related concepts laid out by
semantic closeness ( distance encodes similarity ). Click focuses;
" Open in Graph " hands off to graphical_graph.
Consumes semantic_signals and relationship_signals.
- status
- incomplete
ownership_distribution
reqlan rq/extension/local-context/context-scope-v2.rq
Horizontal author share bars ( bus-factor at a glance ).
Consumes development_history_signals ownership and risk_signals
( e. g. single_contributor ).
- status
- incomplete
historical_replay_slider
reqlan rq/extension/local-context/context-scope-v2.rq
Time slider across the graph ( e. g. 2023 → Now ). Nodes and edges appear /
disappear; dependencies animate. Extremely powerful for architectural
storytelling; performance-capped neighbourhoods only in the activity bar;
fuller replay in Ideas Summary.
Consumes temporal_signals, requirement_lifecycle_signals,
relationship_signals.
- status
- incomplete
requirement_card
reqlan rq/extension/local-context/context-scope-v2.rq
GitHub-issue-style compact card for search results and lists:
name, stability chip, meter %, last edited, ref / impl / test counts,
urgency flag ( e. g. recently changing ).
Composes stability_meter, churn_heat_bar, dependency_pulse
as optional rows — not all at once by default ( token / UI density ).
- status
- incomplete
context_radar
reqlan rq/extension/local-context/context-scope-v2.rq
Polar / radar chart of context richness axes ( Tests, Docs, Dependencies,
History, AI, … ). Filled polygon shows what the current
context_footprint actually covers.
- status
- incomplete
activity_constellation
reqlan rq/extension/local-context/context-scope-v2.rq
Spatial glow of nodes by activity ( GitHub-contribution feel, but layout-
aware ). Shows hotspots without a separate legend dump.
Complements hotspot_overlay; prefer one encoding per surface to avoid
competing visual channels.
- status
- incomplete
impact_radius
reqlan rq/extension/local-context/context-scope-v2.rq
On select / focus, fade in affected neighbours; opacity ∝ downstream impact.
Consumes relationship_signals and risk_signals. Works in miniature
graph and Ideas Summary graph.
- status
- incomplete
ai_readiness_gauge
reqlan rq/extension/local-context/context-scope-v2.rq
Ready-to-assist gauge: requirements ✓, implementation ✓, history ✓,
tests ✕, risk low — plus readiness %. Tells the user whether AI has enough
synthesized context before ai_add_to_context / export.
Pairs with context_fingerprint ( what is in context ) vs readiness
( is it enough / safe ).
- status
- incomplete
semantic_diff_viewer
reqlan rq/extension/local-context/context-scope-v2.rq
Conceptual change summary instead of ( or above ) line diffs:
Added / Changed / Removed ideas or policies, plus impact count
( e. g. 17 requirements ). Higher signal for AI and review than textual diffs alone.
Consumes semantic_signals, relationship_signals,
development_history_signals.
- status
- incomplete
project_weather
reqlan rq/extension/local-context/context-scope-v2.rq
Synthesized workspace health widget — the engineering " dashboard " glance:
Stable / Risk / Momentum / Knowledge / Recent Change, or compact meters
for Project Health, Momentum, Risk, Confidence.
Consumes synthesized_context across risk_signals,
project_activity_signals, quality_signals, and base_signals
( per-base readiness when multiple bases exist ). Belongs in activity bar
workspace lens / Ideas Summary index panel — not as competing hero noise
on every focus.
- status
- incomplete
context_fingerprint
reqlan rq/extension/local-context/context-scope-v2.rq
Compact bars of what the current AI / composed context actually contains:
Files, Requirements, History, Architecture, Git, Diagnostics, Coverage.
Lets the user see expansion when LLM reports " context expanded "
( ai_context_export, ai_integration ).
Hover / info / drill-down affordances: tooltip_detail, fingerprint_axis_drilldown.
- status
- incomplete
widget_composition_rules
reqlan rq/extension/local-context/context-scope-v2.rq
Show-don ' t-tell without dashboard clutter.
- items
- one_job { Each pane region hosts one primary widget job; secondary widgets collapse behind chevrons or appear on hover. }, shared_signals { Widgets never own private analyses — they bind to named signal / synthesis fields so graph, AI, and UI stay consistent. }, density_tiers { Focus hero: at most timeline + one meter + one pulse. Cards/lists: requirement_card defaults; expand for sparklines. Workspace: project_weather + activity_river + optional fingerprint. Graph: pick one of hotspot / constellation / impact encoding per view mode. }, token_discipline { AI export prefers synthesized meters and short stories from widgets (stability, risk, coverage gaps) over enumerating every signal — aligned with ai_integration and ai_context_export. }
- status
- incomplete
implementation_priority_v2
reqlan rq/extension/local-context/context-scope-v2.rq
After v1 implementation_priority is solid:
1. context_model_layers types: sources → signals → synthesis contracts
( extend analytical context model; keep v1 dimensions as sources ). ✓
2. Seed signal producers: development_history_signals,
requirement_lifecycle_signals, relationship_signals, risk_signals
from index + git ( reimagined, not staged / unstaged-only ). ✓ ( thin )
3. synthesized_context rollups for focus entity ( stability, confidence,
AI risk, coverage ). ✓
4. First widgets on focus hero: stability_meter, dependency_pulse,
timeline_ribbon, churn_heat_bar. ✓
5. requirement_card in search / Ideas Summary lists;
context_fingerprint + ai_readiness_gauge on AI context export. ✓
6. Graph overlays: hotspot_overlay, impact_radius. ✓
7. Workspace glance: project_weather, activity_river,
architectural_map. deferred
8. Deeper storytelling: historical_replay_slider, semantic_diff_viewer,
relationship_cloud, traceability_matrix. deferred
- status
- in-progress
context_scope
reqlan rq/extension/local-context/context-scope.rq
Reqlan sidebar and AI workflows reason about a composed reqlan_context_model, not a single " current file " blob.
Context applies to **any workspace file**, not only `.rq` sources — see any_file_scope.
Context is built from orthogonal context_dimensions that the user can enable, pin, or collapse.
The activity bar scope_pane is the primary surface for inspecting and steering context; context_tray holds the manual_context dimension.
Token discipline per ai_integration: show summaries and counts by default; expand a dimension only on intent.
Parses per reference_wikilink.
Decision-oriented v2 ( sources → signals → synthesis → views → consumers ) and show-don ' t-tell widgets: context_scope_v2.
any_file_scope
reqlan rq/extension/local-context/context-scope.rq
The active editor may be a requirement file or implementation file ( Python, TypeScript, etc. ).
current_file_context must surface requirement links even when the file contains no block ideas.
Signals for non-. rq files ( and. rq files without a caret idea ):
- file_reference_links: `.rq` ideas whose outbound `file_reference` edges target this file path ( for example `./apythonfile.py` ).
- folder_reference_links: `.rq` ideas whose `file_reference` targets a parent folder of this file.
- comment_reference_links: ideas resolved from `rq:…` tokens in this file's comments per references_in_functional_code_comments.
- git_context: focus-centric git history ( recent commits, authors, branch ); working-tree dirty badge secondary.
Focus behaviour:
- `.rq` file with caret in a block → idea focus ( unchanged ).
- Any file with linked requirements → file focus; `effectiveCenterId` defaults to the first linked requirement.
- No links → file focus with empty related lists; graph / refs panes stay idle until a requirement is focused.
Implementation: context-model.ts uses file-path-match.ts and `file_related_requirements` analyser; comment links are also resolved from live buffer text when indexed edges are absent.
file_reference_links
reqlan rq/extension/local-context/context-scope.rq
Matched when an indexed `file_reference` edge target resolves to the active file path ( exact or suffix match ).
folder_reference_links
reqlan rq/extension/local-context/context-scope.rq
Matched when an indexed `file_reference` edge target is a folder prefix of the active file per match_file_reference_target.
comment_reference_links
reqlan rq/extension/local-context/context-scope.rq
Matched from `comment_link` index edges and / or `rq:target` spans parsed from the active buffer.
context_dimensions
reqlan rq/extension/local-context/context-scope.rq
Seven dimensions contribute ideas and files to the effective context footprint.
Each dimension has a stable id, human label, default weight, and a one-line summary for collapsed UI.
- workspace workspace_context
Ambient VS Code workspace chrome and multi-base index glance: discovered bases, active base readiness / idea / edge counts — not a full graph dump. Distinct from the active base source in v2.
- current_file current_file_context
Active editor file. For `.rq`: caret idea, in-file outline, unresolved refs. For any file: any_file_scope links and git badge.
- open_files open_files_context
Other workspace editor tabs currently open ( any language ).
- file_history file_history_context
Session recency of visited workspace files ( navigation history ), distinct from edit history.
- edit_history edit_history_context
Session recency of edited workspace files and caret positions ( typing history ).
- manual manual_context
User-pinned ideas from context_tray and explicit " add to context " actions.
- git git_context
Focus-centric development history ( branch, recent commits, authors ) per git_information_capture; working-tree changes demoted.
reqlan_context_model
reqlan rq/extension/local-context/context-scope.rq
Canonical composed context per context-model.ts.
Implementation: context-model.ts.
- context_focus is the single anchor ( idea, file, selection, or none ).
- context_dimensions each contribute context_contribution records with counts and summary lines.
- context_footprint merges enabled dimensions into deduped idea / file sets and an `effectiveCenterId` for graph / refs panes.
- `currentFileSlice` is the projection used when the current-file lens is expanded. Includes `isRqFile`, `referencingIdeas`, `commentLinkedIdeas`, `folderReferencingIdeas`, and optional `gitChange`.
- context_selection when the user highlights a non-empty range spanning one or more `.rq` ideas ( selection_pane ).
- global_hop_depth and dimension_hop_control overrides on the model.
Host increments `revision` when any dimension or hop depth changes; webview ignores stale posts by revision.
context_focus
reqlan rq/extension/local-context/context-scope.rq
kind: idea | file | selection | none.
When sync-with-editor is on, focus follows the caret idea in an active `.rq` editor, or file / selection context otherwise.
When pinned, focus stays on the pinned idea until cleared.
Selection focus applies when the user highlights text spanning one or more ideas ( selection_pane ).
context_selection
reqlan rq/extension/local-context/context-scope.rq
Union of ideas whose line ranges overlap the editor selection in a `.rq` file.
Drives selection_pane and contributes idea ids to context_footprint.
context_contribution
reqlan rq/extension/local-context/context-scope.rq
Per dimension: id, label, enabled, pinned, weight, ideaCount, fileCount, summary, hopDepth, supportsHopControl.
Disabled dimensions do not add to context_footprint but may still show a muted chip with zero count.
Pinned dimensions stay expanded in scope_pane_design until collapsed by the user.
Graph-searchable dimensions expose per-lens hop overrides via dimension_hop_control.
global_hop_depth
reqlan rq/extension/local-context/context-scope.rq
Session default hop depth ( 1 - 4 ) stored in context-session.ts.
Drives graph slice expansion, reference list breadth, ancestor chain depth, and composed context export.
Surfaced in hop_depth_control and echoed on reqlan_context_model. globalHopDepth.
dimension_hop_control
reqlan rq/extension/local-context/context-scope.rq
When a graph-searchable dimension lens is expanded in scope_pane_design, show a local ** − / value / + ** pair.
Applies to current_file_context, open_files_context, file_history_context, edit_history_context, and manual_context — not workspace_context or git_context.
Per-dimension override inherits global_hop_depth until the user adjusts it; stored in dimensionHopDepth on the session and model.
Edge cases match hop_depth_control: disable − at min, + at max, clamp on apply.
context_footprint
reqlan rq/extension/local-context/context-scope.rq
Merged view across enabled dimensions.
- deduped idea ids and file uris with provenance ( which dimensions contributed each entry ).
- `summaryLine`: compact human text, e. g. " this file · 3 open · 2 git · 1 pinned ".
- `effectiveCenterId`: graph / refs / ancestors panes use this; defaults to focus idea, selection's first idea, first linked requirement for non-. rq files, else first idea in current file.
scope_pane_design
reqlan rq/extension/local-context/context-scope.rq
The scope pane uses a **focus + lens** layout — not seven stacked lists.
The experience should feel more like a wiki than a table: surfaced ideas, files, folders, commits, authors, and related context should prefer rich cross-links and drill-in navigation over flat tabular presentation.
Grouping should adapt to available context rather than staying fixed: file-heavy views may group by folder / path, development-history views may group by git recency / authorship / churn, and mixed views should choose the most explanatory structure for the current focus.
- items
- focus_hero { Always visible when focus is non-none: idea name (or file name), status/tags, path:line, one-line summary. For non-.rq files: show git chip and up to four linked requirements inline. Primary actions: open source, pin to manual_context, copy markdown / composed context. }, lens_strip { A single horizontal strip of dimension chips (icons + short labels + counts). - Filled chip = dimension enabled and contributing to context_footprint. - Outline chip = disabled or empty. - Click toggles enabled (except workspace, always ambient). - Alt-click or chevron expands that dimension's detail panel below the strip (only one expanded at a time). }, footprint_line{ One muted line under the lens strip: context_footprint.summaryLine. Replaces listing every dimension's items when collapsed. }, expanded_lens_panel{ Content depends on which lens is expanded: - current_file: for `.rq` — in-file idea list + nested outline; for other files — grouped file_reference_links, comment_reference_links, folder_reference_links. - open_files / file_history / edit_history: compact scrollable file rows (max 8 visible); click opens file; **Refs** loads linked requirements lazily via `loadFileLens`. - git: history-first panel per git_history_lens — branch/HEAD header, focus commit trail, authors; dirty working tree nested secondary. - manual: chips from tray with remove. - workspace: link to workspace_panel.workspace_pane / Ideas Summary — no duplicate index UI. }, anomaly_strip Optional row for unresolved refs or index errors affecting focus file — one line, clickable., Collapsed_default focus hero + lens strip + footprint line. No outline tree until user expands current_file lens on a `.rq` file.
ai_context_export
reqlan rq/extension/local-context/context-scope.rq
header_buttons **Context** copies the composed reqlan_context_model as markdown: effective-centre requirement, non-. rq link sections, selection, pinned tray, and footprint summary.
ai_add_to_context should prefer the same composed context when the activity bar index is ready.
workspace_context
reqlan rq/extension/local-context/context-scope.rq
weight: 0. 1
Always on; contributes multi-base readiness and counts ( active base + sibling summary ) unless user opens workspace pane.
" Workspace " here means the VS Code workspace surface and ambient index health — not a single ontology base.
Active-base routing for focus / graph / refs follows implied_context; see context_sources `base`.
current_file_context
reqlan rq/extension/local-context/context-scope.rq
weight: 1. 0
Default enabled and expanded lens when a workspace file is active.
open_files_context
reqlan rq/extension/local-context/context-scope.rq
weight: 0. 6
Default enabled; summary lists tab count.
file_history_context
reqlan rq/extension/local-context/context-scope.rq
weight: 0. 4
Default enabled; capped list ( configurable, default 12 ).
edit_history_context
reqlan rq/extension/local-context/context-scope.rq
weight: 0. 5
Default enabled; capped list ( default 12 ); entries include last line touched.
manual_context
reqlan rq/extension/local-context/context-scope.rq
weight: 0. 9
Enabled when tray non-empty; pins override sync focus for `effectiveCenterId` when user chooses " focus pinned ".
git_context
reqlan rq/extension/local-context/context-scope.rq
weight: 0. 7
Should detect symbol lifecycle using symbol identity rather than line history for creation: who introduced the symbol, when it was introduced, who last meaningfully changed it, the total number of changes, and the relative change rate versus peer symbols.
Default enabled when repository detected.
Primary: focus-centric git history — branch, HEAD short hash, recent commits touching the focus file / idea, top authors.
Summary prefers history richness ( e. g. " main · 3 commits · 2 authors " ), not staged / unstaged counts.
Working-tree dirty files remain available as a demoted nested section and optional footprint contributors.
Focus hero shows a history cue ( last commit age / branch ) instead of a staged / unstaged chip.
Consumes git_information_capture and development_history_signals.
Windows `git` spawns stay hidden per consumption_silence.
UI: git_history_lens.
implementation_priority
reqlan rq/extension/local-context/context-scope.rq
1. any_file_scope types and context-model.ts builder.
2. Host refresh for any workspace file; git / all-tab collection.
3. scope_pane_design non-. rq focus hero and grouped link panels.
4. context_selection + selection_pane.
5. Lazy `loadFileLens` for file-list dimensions.
6. ai_context_export.
7. graph_path_walk ( future pane / Ideas Summary handoff ).
graph_path_walk
reqlan rq/extension/local-context/graph-path.rq
Future capability: walk the requirement graph **point-to-point** between two chosen ideas.
Complements the activity bar's single-centre neighbourhood ( miniature_graph_pane ) and Ideas Summary's unconstrained graph tab ( graphical_graph ).
problem
reqlan rq/extension/local-context/graph-path.rq
Users often need to answer: " How does requirement A relate to requirement B? " — not the full ego-graph around A, and not an unbounded workspace dump.
Today they manually expand hops or search references. A dedicated path walk would make dependency chains, impact routes, and gap analysis inspectable in the sidebar or graph tab.
path_query
reqlan rq/extension/local-context/graph-path.rq
Inputs:
- `fromIdeaId` ( source node )
- `toIdeaId` ( target node )
- optional `maxDepth` ( `graphHopDepth` in defaults.json )
- optional `edgeKinds` filter ( references, file_reference, incompatible, … )
- optional `direction` ( undirected default, or outbound-only / inbound-only for directed traces )
Output: path_result — zero or more shortest paths through the indexed graph, capped for token and UI limits.
path_result
reqlan rq/extension/local-context/graph-path.rq
- `found`: boolean
- `paths`: ordered list of graph_path ( typically top 1 – 3 shortest )
- `truncated`: true when search hit depth or branch limits
- `summaryLine`: e. g. " A → implements → B → depends on → C " for collapsed UI
graph_path
reqlan rq/extension/local-context/graph-path.rq
Ordered nodes and edges from source to target.
Each step records idea id, name, status, edge kind, and optional snippet / line for the traversed edge.
Paths with unresolved hops are marked broken; UI offers jump-to-source like reference_lists_pane.
path_ui_design
reqlan rq/extension/local-context/graph-path.rq
Entry points:
- Activity bar: " Path to … " on focus hero when a second idea is pinned or selected ( manual_context + selection_pane ).
- Ideas Summary graph tab: shift-click two nodes to set endpoints.
- Command palette: `Reqlan: Find path between requirements`.
Presentation ( sidebar-first ):
- Collapsed: path_result `summaryLine` under the scope footprint line.
- Expanded: vertical stepper ( breadcrumb ) with edge kind labels; optional overlay on graph_library highlighting only path edges / nodes.
- When no path: show closest partial path or " no connection within N hops " with expand-in-Summary action.
Performance:
- BFS / bidirectional BFS on sqlite edge tables via local_graph_analysis — never materialise full workspace graph.
- Debounce endpoint changes; cache last path per `(from,to,depth)` revision tied to index catalog generation.
relationship_to_context
reqlan rq/extension/local-context/graph-path.rq
Path endpoints should default from context_focus and context_footprint.
A successful walk contributes traversed idea ids to a transient " path context " slice suitable for ai_context_export without pinning every intermediate node.
implementation_notes
reqlan rq/extension/local-context/graph-path.rq
Analytical: add `findPathsBetween(store, fromId, toId, options)` returning path_result.
Wire: new `loadGraphPath` message alongside existing `loadGraph` / `loadAncestors`.
UI: defer dedicated pane until selection_pane and composed context are stable; prototype in Ideas Summary graph tab first.
create_requirement
reqlan rq/extension/mutation/mutation-hooks.rq
The extension should provide a command to create a new requirement idea in an appropriate. rq file.
New requirement creation should offer sensible defaults for name, body, and file placement.
split_requirement
reqlan rq/extension/mutation/mutation-hooks.rq
The extension should provide a command to split one requirement into two or more separate ideas.
Splitting should preserve references and attributes according to user selection.
copy_requirement
reqlan rq/extension/mutation/mutation-hooks.rq
The extension should provide a command to copy an idea or requirement to another file or ideaset.
Copy should optionally rewrite local references to match the destination context.
merge_requirements
reqlan rq/extension/mutation/mutation-hooks.rq
should combine requirement attributes, and any references through the codebase.
rename_file
reqlan rq/extension/mutation/mutation-hooks.rq
this should update any referencess in rq files ( imports, inline references, etc )
it should also update any inline references in functional code files - per functional-code-comment-references.rq and comment_reference_refactor_support
Renaming a folder updates references to that folder and to every file inside it.
The index watcher must not drop the pre-move file before inbound import planning
( refactor_file_moves ).
See also refactor_file_moves and refactor_changes.
Implemented by file-move-plan.ts, expand-renamed-paths.ts, register-file-mutation-hooks.ts, pending-rename-paths.ts, file-path-rewrite.ts, and collect-inbound-referencers.ts.
- tests
- file-path-rewrite.test.ts:updates inbound import path when the target file moves, file-path-rewrite.test.ts:updates a folder reference when the folder is renamed, expand-renamed-paths.test.ts:pairs each file under a renamed folder with its old path, pending-rename-paths.test.ts:suppresses watcher delete of the pre-move file until cleared
move_file
reqlan rq/extension/mutation/mutation-hooks.rq
if a file is moved, a prompt should be shown to the user to update any references in the file to the new path.
if multiple files are moved there should be only one prompt.
the trigger should only happen if the reqlan file has inbound or outbound references, or the non-reqlan file has inbound reqlan references.
" reqlan wants to make refactoring changes to your codebase. Do you approve? "
" yes ", " no ", " view changes "
See also refactor_file_moves.
Implemented by register-file-mutation-hooks.ts, show-mutation-approval.ts, and file-mutation-gate.ts.
- tests
- file-path-rewrite.test.ts:updates paths when a file moves to a sibling directory, file-path-rewrite.test.ts:finds import and embedded paths in rq files, file-path-rewrite.test.ts:finds rq comment paths in code files
refactor_changes
reqlan rq/extension/mutation/refactor_support.rq
On rename, move, or delete of files or symbols, the extension should update the
idea index, import statements, embedded file references, comment references, and
other idea references that are affected.
The index should be resilient to duplication, particularly when ideas move between files:
the old hosting file URI must be cleared before or when the destination is reindexed.
refactor_file_moves refactor_symbol_rename refactor_symbol_move refactor_symbol_delete comment_reference_refactor_support
Implemented by workspace-index.ts, index-service.ts, reqlan-idea-refactor.ts, and register-file-mutation-hooks.ts.
refactor_file_moves
reqlan rq/extension/mutation/refactor_support.rq
The extension should watch for file moves and renames, including a renamed folder.
A folder rename is expanded to every file inside it, then the index is migrated for moved
. rq files, and imports and path references are updated both inside the moved file ( outbound )
and in other files that pointed at it or at the folder ( inbound ), including comment paths in code files
( comment_reference_refactor_support ).
Import-root aliases such as `@/old/file.rq` are rewritten when that target moves ( `@/new/file.rq` ).
There should be a single prompt per batch asking whether to apply path updates,
aligned with move_file and rename_file.
While a rename is in flight, the index file watcher must not delete the pre-move URI
before inbound import planning runs — `onWillRenameFiles` marks pending paths and
`migrateRenamedFile` clears the old URI after path edits are planned.
Implemented by register-file-mutation-hooks.ts, expand-renamed-paths.ts, file-move-plan.ts, file-mutation-gate.ts, collect-inbound-referencers-core.ts, pending-rename-paths.ts, index-service.ts, file-path-rewrite.ts, and reqlan-path-references.ts.
- tests
- file-path-rewrite.test.ts:updates inbound import path when the target file moves, file-path-rewrite.test.ts:preserves extensionless inbound paths, file-path-rewrite.test.ts:buildInboundPathRewriteEdits quotes replacement paths, file-path-rewrite.test.ts:updates paths when a file moves to a sibling directory, file-path-rewrite.test.ts:finds comment paths in moved rq files together with imports, file-path-rewrite.test.ts:updates a folder reference when the folder is renamed, file-path-rewrite.test.ts:updates an aliased path when the target folder is renamed, collect-inbound-referencers.test.ts:includes comment_link target files when an rq file moves, expand-renamed-paths.test.ts:pairs each file under a renamed folder with its old path, pending-rename-paths.test.ts:suppresses watcher delete of the pre-move file until cleared, pending-rename-paths.test.ts:suppresses deletes under a renamed folder
refactor_symbol_rename
reqlan rq/extension/mutation/refactor_support.rq
Syntactic symbols ( ideas, ideasets, import aliases, and import paths ) should be
renamable via the editor rename action ( F2 / LSP rename ).
Rename should update AST references across. rq files and matching `rq:idea`
comment idea tokens in source files ( comment_reference_refactor_support ).
The Rust server renames open buffers, open comment buffers, and closed files reached via the ideas index.
Non- `.rq` comment rename stays on the host provider until Rust owns those buffers.
refactor_support
Implemented by session.rs, reqlan-rename-provider.ts, reqlan-comment-rename.ts, reqlan-name-provider.ts, and register-comment-rename-provider.ts.
- implementation
- session.rs, analysis.rs
- status
- done
- tests
- session.rs:completion_rename_and_code_action, session.rs:attribute_catalog_completion_and_find_references, rename-provider.test.ts:rename updates declaration and wikilink references, rename-provider.test.ts:rename also updates rq comment idea tokens in the same document, comment-rename.test.ts:builds rename edits for matching comment idea tokens, linking.test.ts:rename finds all idea references including wikilinks
refactor_symbol_move
reqlan rq/extension/mutation/refactor_support.rq
An idea can move to another existing `.rq` file from a code action or the command_palette.
Palette commands use the idea under the cursor, or a pick list when the cursor is not on an idea.
1. Move idea ( `reqlan.refactor.moveIdea` )
- Cut the declaration from the source file.
- Insert it into the destination file.
- Remove source imports that the move makes unused.
- Add the imports that the moved idea needs to the destination.
- If the source file still refers to the idea, import it from the destination.
- Rewrite comment references per comment_reference_refactor_support.
- Reindex without duplicate idea rows for the old hosting file.
2. Move idea content ( `reqlan.refactor.moveIdeaContent` )
- Do the same as ( 1 ).
- Always import the destination file in the source.
- Leave a one-liner stub in the source: `idea_name idea_name`.
Do not overlap decompose: decompose writes a new file. Move and decompose share the resolve-plan-apply sequence in idea-extract-flow.ts.
refactor_support refactor_changes
- implementation
- reqlan-idea-refactor.ts, reqlan-idea-move-imports.ts, reqlan-code-action-provider.ts, code_actions.rs, idea-extract-flow.ts, register-idea-refactor-commands.ts
- status
- done
- tests
- idea-refactor.test.ts:move plan cuts from source and inserts into destination, idea-refactor.test.ts:move plan rewrites qualified comment paths for the moved idea, idea-refactor.test.ts:move plan removes unused source imports and copies them to destination, idea-refactor.test.ts:move plan adds a sibling import on the destination, idea-refactor.test.ts:move content plan leaves a source stub that imports the moved idea, code-actions.test.ts:offers move and delete actions at an idea declaration, code_actions.rs:offers_move_and_delete_actions_at_an_idea_declaration, extension-package.test.ts:package.json contributes move idea and move idea content commands
refactor_symbol_delete
reqlan rq/extension/mutation/refactor_support.rq
An idea declaration should offer a code action to delete it and update references.
Deleting should remove the declaration, clear or rewrite AST and comment references
that targeted it ( comment_reference_refactor_support ), and reindex affected files.
refactor_support refactor_changes
Implemented by reqlan-idea-refactor.ts, reqlan-code-action-provider.ts, code_actions.rs, and register-idea-refactor-commands.ts.
- tests
- idea-refactor.test.ts:delete plan removes declaration and bracket references, idea-refactor.test.ts:delete plan removes matching comment references, code_actions.rs:offers_move_and_delete_actions_at_an_idea_declaration
comment_reference_refactor_support
reqlan rq/extension/mutation/refactor_support.rq
File and symbol refactors must update comment_reference tokens in code files and in `.rq` comments.
When a file or folder moves or is renamed, rewrite `rq:idea` paths relative to the referencing file: outbound paths inside the moved file, and inbound paths in other files that pointed at it. Aliased paths such as `rq:idea` keep the alias and update the remainder.
When an idea is renamed, update matching comment idea tokens.
When an idea moves to another `.rq` file, rewrite qualified comment paths that targeted the old file for that idea. Pathless `rq:idea` tokens stay as name-only links.
When an idea is deleted, remove comment references that targeted it.
Relates to refactor_file_moves, refactor_symbol_rename, refactor_symbol_move, refactor_symbol_delete, refactor_changes, move_file, rename_file, references_in_functional_code_comments.
- implementation
- reqlan-path-references.ts, file-path-rewrite.ts, reqlan-idea-refactor.ts, reqlan-comment-rename.ts, file-move-plan.ts, expand-renamed-paths.ts, collect-inbound-referencers.ts, collect-inbound-referencers-core.ts, register-idea-refactor-commands.ts
- status
- done
- tests
- file-path-rewrite.test.ts:rewrites inbound comment paths when the target rq file moves, file-path-rewrite.test.ts:finds comment paths in moved rq files together with imports, idea-refactor.test.ts:move plan rewrites qualified comment paths for the moved idea, idea-refactor.test.ts:delete plan removes matching comment references, collect-inbound-referencers.test.ts:includes comment_link target files when an rq file moves, comment-rename.test.ts:builds rename edits for matching comment idea tokens
graph_design
reqlan rq/extension/presentation/graph.rq
The graph should show nodes for ideas and files and edges for references.
Used by Ideas Summary, activity-bar minigraph, and export previews.
graph_library
reqlan rq/extension/presentation/graph.rq
Reusable cytoscape-based graph visualization library for force-directed and compound graphs.
Provides a mount → sync slice → layout → optional live physics → destroy lifecycle with a simplified API.
Implementation lives in graph-cytoscape.ts, graph-cy-controller.ts, graph-cy-elements.ts, graph-cy-interactions.ts, graph-cy-highlight.ts, graph-physics.ts, graph-groups.ts, and graph-theme.ts.
Ideas Summary re-exports the shared modules from lib for backward-compatible import paths.
Consumers pass a node / edge slice and sync options; the library owns the cytoscape instance, diffing, layout runs, and optional continuous physics.
technology
reqlan rq/extension/presentation/graph.rq
uses cytoscape. js for the graph layout and canvas.
cytoscape-fcose provides the batch force-directed settle; cytoscape-cola is available as a batch layout option.
continuous ( " live " ) physics is a custom simulation in graph-physics.ts.
the controller initialises cytoscape with Canvas 2 D only ( pixelRatio 1, no WebGL ) so webviews do not break on unresolved CSS variables.
Body prose with inline parentheses must parse per lists and round_brackets.
graph_cytoscape
reqlan rq/extension/presentation/graph.rq
builds cytoscape elements and stylesheet from a generic node / edge slice.
registers batch layout options ( fcose, cola, breadthfirst, circle, concentric, grid, random ) and seeds positions for new nodes.
exposes CompoundBasis ( single-membership folder tree ) and GroupBasis ( flat multi-membership ) as grouping inputs.
per graph-cytoscape.ts and graph-theme.ts.
getLayoutConfig sets fit: false for initial ( mode = = = ' initial' ) batch layouts so auto_reframe owns the first viewport fit; relayout modes may still fit via the layout algorithm.
graph_cy_controller
reqlan rq/extension/presentation/graph.rq
the cytoscape object should use event driven patterns; lifecycle is documented here.
GraphCyController in graph-cy-controller.ts owns the cytoscape instance with inline lifecycle state ( idle, syncing, layouting, physics ).
syncGeneration cancels stale layout callbacks when the slice changes mid-layout.
Selection and drag-pinned positions are tracked in userPositionedNodes on the controller.
syncSlice diffs elements ( add / remove / update the delta ) via graph-cy-elements.ts so surviving nodes keep positions; requestLayout restarts the active algorithm and clears user pins.
Pointer / selection wiring lives in graph-cy-interactions.ts; compound hover / selection / title-hit in graph-cy-highlight.ts.
Compound grab / drag / free pins and unpins all childless descendants so live physics does not snap members back while the container moves; released child positions are stored in userPositionedNodes.
File compounds ( `isFileCompound` ): title-band tap or double-tap opens the hosting `.rq` via onOpen ( compoundId ); GraphView resolves `compound:rq-file:…` to a file URI.
Live physics is the custom simulation in graph-physics.ts; one instance persists with the cytoscape instance and is paused / resumed, never rebuilt. Grabbing a node pins it in the running sim ( its live position keeps exerting forces ); release unpins with no restart and no snap.
ResizeObserver debounces cy. resize ( ) and re-triggers a pending sync when the container gains size.
Mount only while the graph container is visible and non-zero — do not keep cytoscape alive under display: none; WebGL init on a zero-size hidden container can break the host webview before messaging is attached.
Viewport fitting per reframe_view; tracks lastSyncedNodeSetKey vs fittedNodeSetKey to drive auto_reframe.
Label visibility per graph_label_modes / graph_label_auto: setLabelMode updates text-opacity from zoom ( and hover / drag force-opaque in auto ).
graph_cy_elements
reqlan rq/extension/presentation/graph.rq
syncGraphElements diffs the live cytoscape graph against the desired slice rather than remove-all / add-all on every sync.
Surviving nodes keep positions; only added / removed / updated elements move.
Mutable data fields ( label, color, flags ) can update without a structural relayout.
per graph-cy-elements.ts.
webview_threading
reqlan rq/extension/presentation/graph.rq
VS Code webviews run JavaScript on a single main thread, like a browser tab.
Heavy synchronous work — cytoscape layout iterations, large element builds, unbounded loops — blocks UI updates until it finishes.
Layout iteration count scales with node count ( capped ) rather than running unbounded defaults.
Do not restart layout synchronously on layoutstop; hand off to the graph-physics simulation, which integrates one step per requestAnimationFrame instead of blocking.
layout_physics
reqlan rq/extension/presentation/graph.rq
defaults to force-directed layout ( fcose ) with animation on, but callers can select other options offered by cytoscape. js.
a toggle leaves layout animation and live physics on for force-directed layouts instead of settling immediately.
live physics is the custom obsidian-style simulation in graph-physics.ts ( force core: physics-core.js ), regardless of which force-directed batch layout produced the initial settle.
forces are central gravity toward the centroid, linear edge springs, and inverse-square node repulsion; every childless node participates, including disconnected orphans.
group container constraints live in graph-groups.ts: each leaf carries data ( ' groupIds' ); disjoint groups are pushed apart after batch cola / fcose and during Animate; groups that share a member ( multi-membership, e. g. tags ) may overlap around the shared node.
the simulation is deterministic ( no randomness ) and converges slowly over tens of seconds, then sleeps; interactions wake it instead of restarting it.
dragging pins the held node while the sim keeps running around it; release rejoins the node at rest with no snap; clicks never disturb the sim.
Dragging a compound container pins every childless descendant for the same reason ( see graph_cy_controller ).
cycling the Animate toggle pauses and resumes the same simulation state, so it converges to the same attractor as leaving it on.
view_controls
reqlan rq/extension/presentation/graph.rq
pan, zoom, and drag repositioning are supported on the canvas.
Leaf nodes and compound containers are both draggable; compound drag moves members with the parent.
zoom range is wide rather than tightly capped so users can inspect fine detail or see the whole neighbourhood.
reframe_view fits and centres the camera on the graph bounding box without changing node positions or restarting layout / physics.
Zoom and Fit must continuously drive graph_label_auto opacity when Labels is in auto mode.
graph_labels
reqlan rq/extension/presentation/graph.rq
Graph node labels must show the full idea name without character truncation.
Wrapping is allowed; ellipsis truncation of display names is not.
Shared contract for Ideas Summary ( cytoscape ) and HTML export ( canvas ); surface-specific wiring lives under consumers.
graph_label_modes
graph_label_auto
- status
- done
graph_label_modes
reqlan rq/extension/presentation/graph.rq
Every interactive graph should provide a Labels control that cycles auto ( default ), on, and off without changing graph membership.
On forces full opacity; off hides all labels; auto follows graph_label_auto.
Reset / default restore auto.
Ideas Summary: control in GraphControls.svelte, mode persisted via graph_ui_persistence.
HTML export: control in mod.rs / app.js.
Driven by the same viewport zoom as view_controls.
- implementation
- graph-cy-controller.ts, GraphControls.svelte, graph-ui-state.ts, app.js, mod.rs
- status
- done
- tests
- graph-ui-state.test.ts, html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
graph_label_auto
reqlan rq/extension/presentation/graph.rq
In Labels auto mode, visibility follows viewport zoom continuously rather than a hard cut. ( fade )
Below a low zoom threshold labels are fully hidden; above a slightly higher threshold they are fully opaque; between those thresholds opacity ramps briefly through a muted / semi-transparent phase ( GRAPH_LABEL_FADE_START → GRAPH_LABEL_FADE_END ).
Labels start fully invisible during graph initialisation and layout settling so text paint does not lag those phases; zoom fade only applies once settle / reframe has finished.
Hovered or dragged nodes remain fully opaque even when ambient auto opacity is low or zero.
Zoom and Fit from view_controls / reframe_view must update this opacity on each paint or zoom event.
Applies to Ideas Summary GraphCyController and HTML export canvas graph alike.
- implementation
- graph-cy-controller.ts, graph-cytoscape.ts, app.js
- status
- done
- tests
- graph-label-opacity.test.ts, html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
graph_status_tag_filters
reqlan rq/extension/presentation/graph.rq
Status and tag graph filters are searchable checkbox dropdowns ( still a dropdown trigger; multi-select via checkboxes; OR within each field ).
They must distinguish attribute absence from an empty declaration and from a literal unspecified value:
- Not present — attribute key absent ( no `@status` / no `@tags` )
- Empty — attribute declared with no value ( `@status`, `@tags`, `@status ""`, bare flag )
- unspecified — literal authored value " unspecified "
Do not invent unspecified for missing attributes in rollups, clusters, or filter options.
Special options render differently from concrete values ( italic muted Not present; info-tint Empty; warning-tint unspecified ).
Shared helpers live in filter-specials.ts.
Surfaces: Ideas Summary SearchableCheckboxDropdown; HTML export SCD in app.js.
- implementation
- filter-specials.ts, snapshot.rs, mod.rs, app.js, html_utils.rs, webview-graph-queries.ts, sqlite-store.ts, SearchableCheckboxDropdown.svelte, GraphControls.svelte, GraphView.svelte, messages.ts
- status
- done
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets, filter-specials.ts
reframe_view
reqlan rq/extension/presentation/graph.rq
Shared viewport behaviour for every surface that mounts GraphCyController ( Ideas Summary graph tab, activity bar mini graph, and future consumers ).
Implementation: reframeGraphToViewport and GraphCyController. reframeToViewport in graph-cy-controller.ts.
manual_reframe
auto_reframe
reframe_animation
Constants: GRAPH_VIEWPORT_PADDING ( 36 px padding around the element bounding box ), GRAPH_REFRAME_ANIMATION_MS ( 400 ms animated transition ).
Reframes resize the cytoscape container first, then fit all elements and centre the camera.
Does not clear selection, centreId, user-pinned drag positions, or live physics state — viewport only.
manual_reframe
reqlan rq/extension/presentation/graph.rq
Users can explicitly reframe the viewport when pan / zoom has moved the graph off-screen or they want to see the whole neighbourhood again.
- " Fit to view " control in GraphControls.svelte dispatches to GraphView → GraphCyController. reframeToViewport ( ).
- " Fit to view " control in MiniGraphCanvas.svelte calls the same API on the mini-graph controller.
Every graph surface that mounts GraphCyController should expose this control.
auto_reframe
reqlan rq/extension/presentation/graph.rq
The graph should automatically fit to the viewport when the loaded node set changes — without requiring the user to click " Fit to view ".
After each successful syncSlice, GraphCyController compares the sorted node-id set of the incoming slice with fittedNodeSetKey ( the set the viewport was last fitted to ).
When they differ, finishRender triggers an automatic reframe via reframeToViewport.
Triggers when any node is added or removed from the slice ( new neighbourhood, focus change, filter change that changes membership ).
Does not trigger for metadata-only updates on the same node ids ( label, colour, isCenter flag, etc. ) — those keep the user's current pan / zoom.
Does not trigger on requestLayout relayout when the node-id set is unchanged.
reframe_animation
reqlan rq/extension/presentation/graph.rq
The first reframe on a controller mount is instant ( synchronous cy. fit + cy. center ) so the graph appears immediately on first paint.
Every subsequent reframe — automatic ( auto_reframe ) or manual ( manual_reframe ) — animates pan and zoom smoothly over GRAPH_REFRAME_ANIMATION_MS using cytoscape. animate ( { fit, easing: ' ease-out-cubic ' } ).
Callers may pass `reframeToViewport({ animate: false })` to force an instant reframe.
Initial batch layouts use fit: false ( see graph_cytoscape ) so the controller owns the first fit and later animated handoffs are not double-applied.
layout_options
reqlan rq/extension/presentation/graph.rq
- user can select from a dropdown of layout options offered by cytoscape. js
- user can select whether to use compound layouts ( where compound basis is based on the folder structure )
- compound basis should be flexible and expected as an input
compound_graph
reqlan rq/extension/presentation/graph.rq
folder hierarchy is to be supported with compound layouts.
Hosting `.rq` files can also act as compound parents via
file_treatment_toggle ( mode `compound` ).
File compounds are styled distinctly ( ideaset accent, underlined title ), remain draggable with members, and open the hosting file on title click / double-click ( see graph_cy_controller ).
physics_options
reqlan rq/extension/presentation/graph.rq
- user can select from a dropdown of physics options offered by cytoscape. js
- the options for the physics should be exposed to the user in a menu too.
- user can select whether to use live physics / animation
- live physics uses the custom graph-physics simulation; cola remains selectable as a batch layout in the layout dropdown
- Ideas Summary exposes layout, live-physics, and force sliders in GraphControlPanel.svelte
webview
reqlan rq/extension/presentation/webview.rq
Extension webviews are Svelte UIs hosted by the VS Code extension per core.rq.
They should be performance conscious: prefer capped, paginated, or scoped slices and avoid full-graph dumps unless the user explicitly requests one.
The extension host loads compiled assets from `packages/extension/media/webviews/`.
UI state conventions: ui_state_management / webview_app_state.
Webview modules in the extension:
- Ideas Summary — overview, ontology tables ( bases / ideas / ideasets / attributes / references ), graph, and index ( last ): ideas_summary / ideas_summary / ontology_aligned_tabs
- Activity bar — editor-adjacent sidebar panes: activity_bar
- Export form — multi-format graph export: export.rq".export_webview
- Onboarding — first-install / welcome webview: installation_event
ideas_summary_base_scope
reqlan rq/extension/workspace-summary/ideas_summary/base-scope.rq
Ideas Summary is scoped to one base at a time.
- Active base defaults to the longest-matching base root for the focused editor ( implied_context ).
- Chrome includes an explicit base switcher; Overview, Bases, Ideas, Ideasets, Attributes, References, Graph, Timeline, and Index tabs bind to the selected base's index only ( Bases lists all discovered bases; Index is last ).
- Switching base is a pointer swap ( active_base_switch ): pin via `setActiveBaseId`, rebind status / tables / graph UI immediately — do not await sync on the switch call; not-ready bases get fire-and-forget open + soft-sync catch-up.
- Graph UI persistence is per-base: workspaceState key `reqlan.ideasSummary.graphUi.<baseId>` via graph-ui-state.ts.
- Activity bar " Open in Ideas Summary " passes the current active base id into ideas-summary-panel.ts.
- No merged cross-base tables or graphs in this pass ( multi_base_environment ).
- implementation
- ideas-summary-panel.ts
- status
- done
graphical_graph
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
There should be a tab that renders requirement ideas and references as a force-directed web.
The graph tab lives in the Ideas Summary webview per ideas_summary.
UI is implemented in GraphView.svelte.
Graph slices are built in webview-graph-queries.ts and served by ideas-summary-panel.ts.
By default the view focuses on the active editor file's first idea; without a focus it shows a capped slice of matching ideas rather than dumping the full graph.
Users can filter by search text, path, multi-select @ status, and multi-select tags per graph_status_tag_filters.
An " Indirect references " toggle expands neighbourhood depth from 1 to 2 hops.
A " Wildcard refs " toggle includes or hides edges expanded from path + idea wildcards per wildcard_refs_toggle
wildcard_references
A " Files " dropdown selects hosting- `.rq` treatment per file_treatment_toggle
( hidden / compound containers / linked ideaset nodes ), with per-option info tooltips.
Interactive graph controls that also exist on HTML export must stay aligned per webview_export_graph_parity.
Clicking a node opens its source; double-click or " Focus graph " recenters the slice on that idea.
Linked file ideaset nodes and file-compound titles open the hosting `.rq` file per graphical_graph.
External file references render as dashed edges to file nodes; wildcard-fan-out edges render dotted.
A toggleable key explains node colours and edge styles and toggles node-type visibility per key_panel_toggle; a toggleable control_panel exposes layout, physics, and node-budget settings. Key and Controls state persist per workspace via graph_ui_persistence.
Pan, zoom, and drag repositioning per view_controls.
manual_reframe via " Fit to view " in ui_controls; auto_reframe when the loaded node set changes; reframe_animation for smooth transitions after the first paint.
Node text labels per graph_labels, graph_label_modes, and graph_label_auto.
Layout, compound grouping, and live physics behaviour per layout_physics, layout_options, physics_options, and compound_graph.
Cytoscape lifecycle and threading constraints per graph_cy_controller and webview_threading.
library
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
should consume the graph_library
root
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
ui_controls
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
Controls live in GraphControls.svelte and dispatch events to GraphView.
manual_reframe — " Fit to view " calls GraphCyController. reframeToViewport per reframe_view.
auto_reframe and reframe_animation are handled by the shared controller; no extra UI beyond pan / zoom / drag.
Labels control cycles graph_label_modes ( auto / on / off ) and applies graph_label_auto via GraphCyController. setLabelMode.
Files dropdown ( file_treatment_toggle ) uses FileTreatmentSelect.svelte
with Hidden / Compound / Linked options and info tooltips; selection patches `fileTreatment` in graph_ui_persistence.
Status and tag filters are multi-select dropdowns per graph_status_tag_filters.
The Key button toggles a draggable legend panel in GraphKeyPanel.svelte over the graph canvas.
The Controls button toggles control_panel.
Overlay panels ( Key and Controls ) are siblings of the cytoscape mount inside a graph-surface-wrap — never children of the cy container — so native form controls receive pointer events.
wildcard_refs_toggle
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
Toolbar chip " Wildcard refs " ( next to Indirect refs ) on GraphControls toggles `GraphViewQuery.includeWildcardRefs`.
Default true — edges of kind `wildcard_reference` from the indexer fan-out stay visible
( wildcard_reference_edges ).
When false, `buildGraphViewSlice` omits those edges and does not expand neighbourhood through them
( `includeWildcardRefs!== false` normalisation in Ideas Summary host + analytical query ).
Distinct from plain `references` and from the Indirect refs depth toggle; Key legend shows a dotted
" Wildcard reference " row; cytoscape marks `edge?isWildcard` with `line-style: dotted`.
Query field flows Ideas Summary loadGraph → `buildGraphViewSlice` in
webview-graph-queries.ts.
HTML export workspace graph has the same chip ( client filter on embedded edges; dotted stroke ) per
webview_export_graph_parity and html_export_graph_page.
Related: wildcard_references,
wildcard_reference_edges,
index,
graphical_graph, ui_controls, wildcard_refs_toggle.
- implementation
- GraphControls.svelte, GraphView.svelte, messages.ts, ideas-summary-panel.ts, default-queries.ts, webview-graph-queries.ts, extract.rs, extract.rs, graph-cytoscape.ts, graph-theme.ts, global.css, mod.rs, app.js
- status
- done
- tests
- wildcard_reference_edges.rs:stores_wildcard_fan_out_as_wildcard_reference_kind, wildcard_reference_edges.rs:indexer_and_graphical_graph_rq_capture_wildcard_edge_and_toggle_ideas, wildcard_reference_edges.rs, wildcard_reference_edges.rs:stores_wildcard_fan_out_as_wildcard_reference_kind, html_export.rs:html_export_workspace_graph_includes_wildcard_refs_chip_and_edges, html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets, html_export.rs:workspace_graph_includes_every_idea_when_max_graph_nodes_is_below_count
file_treatment_toggle
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
Toolbar dropdown selects how hosting `.rq` files ( implicit ideasets ) appear in the graph —
distinct from explicit AST `ideaset` declarations and from external `file:` reference nodes.
Options ( with info tooltips / help text ):
- invisible / Hidden — no file containers or file leaf nodes; ideas float free
- compound — one compound parent per hosting file ( basename label ); nests under folder / tag
compounds when Controls → Compound is also on. Containers are draggable ( members move with
the box; live physics pins descendants while dragging ). Clicking the title opens the file;
double-click also opens.
- linked / Linked nodes ( default ) — synthetic ideaset-styled leaf per hosting file ( `rq-file:…` ) with `ideaset_member`
edges to ideas in that file; click / dbl-click opens the hosting file like other nodes.
Client reshape via `applyFileTreatment` in
file-treatment.ts; no re-query on mode flip.
Ideas Summary: `FileTreatmentSelect` on GraphControls; persisted as `fileTreatment` in
graph_ui_persistence.
HTML export: same three options via a select; compound boxes are hittable / draggable with
clickable titles; linked nodes carry `pageUrl` / `hostFilePageUrl` for navigation.
Related: graphical_graph, ui_controls, webview_export_graph_parity,
file, ideaset,
html_export_graph_page.
- implementation
- file-treatment.ts, graph-cytoscape.ts, graph-cy-controller.ts, graph-cy-interactions.ts, graph-cy-highlight.ts, FileTreatmentSelect.svelte, GraphControls.svelte, GraphView.svelte, graph-ui-state.ts, mod.rs, app.js
- status
- done
- tests
- file-treatment.ts, graph-ui-state.test.ts, html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets
webview_export_graph_parity
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
Interactive graph behaviour that authors rely on in Ideas Summary must have a matching affordance
on the HTML export workspace graph ( html_export_graph_page ) unless a requirement explicitly
scopes it to one host.
Shared today: Labels auto / on / off, live physics, Fit, status / tag filters, path / search filters,
hide external files, hide ideasets ( explicit AST ), file_treatment_toggle ( dropdown with the same
three modes, compound drag / title-open, linked-node open ), and wildcard_refs_toggle
( default on; dotted wildcard edges ).
Ideas Summary may still differ where the host model differs: Indirect refs rebuilds hop depth via
`buildGraphViewSlice` ( export freezes neighbourhood at snapshot time — no Indirect chip );
Key / Controls panels and node-budget controls are webview-only; export uses client-side filters
on the embedded graph JSON rather than re-querying the index; Ideas Summary uses cytoscape
compound parents while export draws AABB compound boxes on canvas.
When adding a new Ideas Summary graph chip or edge style, update webview_export_graph_parity ( or
document an intentional exception here ) and keep labels / defaults aligned across surfaces.
Related: graphical_graph, webview_export_graph_parity, webview_export_graph_parity, ui_controls,
graph_labels, graph_label_modes, graph_status_tag_filters.
- implementation
- GraphControls.svelte, FileTreatmentSelect.svelte, mod.rs, app.js
- status
- done
- tests
- html_export.rs:html_export_writes_ts_page_template_set_and_embeds_assets, html_export.rs:workspace_graph_includes_every_idea_when_max_graph_nodes_is_below_count, file-treatment.ts, wildcard_reference_edges.rs:stores_wildcard_fan_out_as_wildcard_reference_kind, wildcard_reference_edges.rs:indexer_and_graphical_graph_rq_capture_wildcard_edge_and_toggle_ideas, html_export.rs:html_export_workspace_graph_includes_wildcard_refs_chip_and_edges
graph_loading
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
the extension pushes graphSlice when the index is ready — no empty waitingForIndex wedge.
ideas-summary-panel.ts sets graphSlicePending on loadGraph and delivers the slice when the index becomes ready ( including via index status updates ).
Index status posts must not await graph slice builds, so sync progress keeps updating the Index tab.
webview state in app.svelte.ts is query, slice, loading, rendering, and error only.
App. init attaches the window message listener during App. svelte script setup ( before child onMount ) so loadGraph replies are never dropped.
GraphView marks a slice as synced only in onRendered ( after cytoscape flush + layout ), not before syncSlice is queued.
Webview → extension posts go through vscode.ts which JSON-clones payloads so Svelte $ state proxies are structured-clone safe.
GraphView remount reuses app. graph. slice when present; it only loadGraphs when there is no slice and nothing in flight, or force-retries after an error.
GraphView mounts only while the graph tab is active ( see TabPanels ); per graph_cy_controller do not keep cytoscape alive under display: none.
node_truncation
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
nodes are truncated if there are too many.
the count should be configurable; as should the truncation basis ( last changed.., last accessed.., owned by etc. )
Max nodes and keep-by basis are edited in control_panel; query fields are maxNodes and truncationBasis on GraphViewQuery.
Default budget is GRAPH_MAX_NODES ( 120 ); hard ceiling is GRAPH_NODES_HARD_CAP ( 1000 ) in webview-graph-queries.ts — raise that constant to lift the cap.
Supported bases today: path, git-modified, git-created ( git timestamps from the index ). Last-accessed / owned-by need index fields before UI can offer them.
referenced_files_grouping
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
referenced_files should be grouped into a common node if they're referenced by multiple ideas.
Line numbers should be treated like ideas if specified, such that the reference points to items in rendered graph.
cola_vs_phyics
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
the user should have a constraint based layout; and a physics based layout; and some other options.
key_and_controls
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
there is a toggle that open a key; and a toggle that opens a control_panel.
control_panel
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
Floating panel in GraphControlPanel.svelte, toggled from ui_controls.
Provides layout algorithm selection, live-physics toggle, compound grouping, physics force sliders, max node count, and truncation basis.
Physics tunables call GraphCyController. setPhysicsSettings; node budget changes re-request the graph slice via loadGraph.
Mounted as a sibling of the cytoscape container ( not inside it ) so range sliders and selects work with native browser events.
When positioned, a ResizeObserver on the surface wrap reclamps panelX / panelY so the panel stays fully inside after the webview is resized; Key panel uses the same reclamp.
Open / closed state and all control values persist per graph_ui_persistence.
key_panel_toggle
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
the key panel should be able to toggle inclusion / visibility of the different node types.
Node-type rows in GraphKeyPanel.svelte are toggle buttons; hidden types render dimmed with a struck-through label.
Toggleable types are block, one-liner, ideaset, focused idea, and external file — GraphNodeTypeId in graph-theme.ts, classified per node by graphNodeTypeId ( same priority as node fill colour ).
Linked file ideaset nodes ( `isFileIdeaset` ) classify as ideaset for Key toggles; file compound containers are legend-only ( " File group " ) and follow member visibility like other compounds.
GraphView tracks hidden types and calls GraphCyController. setHiddenNodeTypes in graph-cy-controller.ts, which flags matching nodes with data typeHidden; a display: none stylesheet rule in graph-cytoscape.ts hides them, and cytoscape hides edges whose endpoint is hidden.
Compound containers whose members are all hidden are hidden too. Hiding is client-side visibility only: the slice still contains the nodes, node / edge counts are unchanged, and flags reapply after every slice sync.
Key open state and hidden node types persist per graph_ui_persistence.
graph_ui_persistence
reqlan rq/extension/workspace-summary/ideas_summary/graphical_graph.rq
Key and Controls state is stored in VS Code ExtensionContext. workspaceState under key GRAPH_UI_WORKSPACE_STATE_KEY ( reqlan. ideasSummary. graphUi ).
Shape and normalisation live in graph-ui-state.ts; the host reads / writes it from ideas-summary-panel.ts.
On webview ready the extension posts graphUiState; the webview posts persistGraphUiState ( debounced ) whenever AppState. patchGraphUi runs in app.svelte.ts.
Persisted fields: showKey, showControls, hiddenNodeTypes, layoutId, useCompound, compoundBasisId, animatePhysics, labelMode, fileTreatment, maxNodes, truncationBasis, and the five physics sliders ( gravity, repulsion, linkStrength, linkDistance, damping ).
GraphView in GraphView.svelte treats app. graph. ui as the source of truth and applies layout / physics / hidden types / label mode / fileTreatment to GraphCyController when those fields change.
The first graph load waits for graphUiState so restored node budget is included in loadGraph.
simple_views
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Ideas Summary tables cover ideas ( title, path / namespace, main and other attributes, reference counts )
and references ( source and target path / namespace, whether in `.rq`, reference type ).
graph_view
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Ideas Summary provides a requirements graph view showing ideas and their references as nodes and edges.
The graph view should support navigation from a node to its source definition in the editor.
Users should be able to filter or focus the graph by file, ideaset, tag, or status.
status_table
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Ideas Summary should render a status table summarising ideas by lifecycle state, priority, and completion.
The status table should support sorting and filtering by tags and attributes.
ide_page_reports
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Ideas Summary provides dedicated report pages inside the IDE ( graph page and status table at minimum ).
Report pages may render computed information that is not present as literal text in source files.
ideas_summary
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
The Ideas Summary webview is a workspace-wide page for tables ( and graph ) summarising ideas
per simple_views and webview.
Tabs align with salient ontology.rq data and HTML export list views ( html_export_list_views ):
ontology_aligned_tabs.
It should be performance conscious and avoid full-graph dumps unless requested by the user.
It should be paginated.
It should be filterable and sortable via a ui-sql layer per table_column_filters and table_column_options.
Webview UI is implemented with Svelte per core.rq
the extension host loads compiled assets from `packages/extension/media/webviews/ideas-summary` ( Vite output of ideas-summary )
table queries are built in webview-table-queries.ts
the extension host forwards query state through ideas-summary-panel.ts
Ideas Summary chrome should include a link that opens export_webview.
Multi-base scope and switcher: ideas_summary_base_scope.
ontology_aligned_tabs
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Tab order: Overview, Bases, Ideas, Ideasets, Attributes, References, Graph, Timeline, Index.
Index is last — workspace index health and maintenance, not the primary browsing surface.
Covers base, idea, ideaset, attribute, reference,
the graph cartography tab, and timeline_page; Overview mirrors HTML export home metrics lightly.
Files / clusters / print families stay export-only for now.
- implementation
- tabs.ts, TabPanels.svelte
pages
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
- ideas summary ideas-summary-panel.ts
- header / status chrome with base switcher and link to export_webview;
error state of the status chrome per error_status_bar
- overview_page OverviewPanel.svelte
- bases_tab BasesTable.svelte
- ideas_list
- ideasets IdeasetsTable.svelte / idea_sets_tab
- filterable and sortable via ui-sql layer; column filters and options
- attributes_tab AttributesTable.svelte
- references ReferencesTable.svelte
- filterable and sortable via ui-sql layer; groupable by reference type per group_by_type
- Graph view: see graphical_graph
- timeline_page TimelinePanel.svelte
- index_panel IndexPanel.svelte ( last tab — index health )
ideas_list
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
- IdeasTable.svelte
- filterable and sortable via TableToolbar.svelte, ColumnFilterRow.svelte, and SortableTh.svelte
- column show / hide via TableOptionsMenu.svelte / table_column_options
- wide tables scroll horizontally in a `.table-scroll` viewport ( columns keep min widths; no crush-to-fit )
- groupable by idea kind ( block / oneliner ) per group_by_type
- other attributes shown as expandable chips per ChipList.svelte
- clicking an attribute chip adds a column, filters to ideas with a non-null value for that attribute, and sorts by it ( combinable with other filters )
- references split into outbound and inbound chip columns with counts
- clicking a reference chip filters ideas that share that edge ( combinable with other filters )
- block idea bodies shown in a scrollable cell per IdeaBodyCell.svelte
- columns for git_idea_timeline_analysis: first committed, last modified, and change count
- read from indexed `git_created_at` / `git_modified_at` / `git_change_count` only
- empty cells until git_dates_background_indexing fills them;
main table load never runs git
ideas_list_git_columns_performance
ideas_list_git_date_format
- implementation
- IdeasTable.svelte, webview-table-queries.ts, sqlite-store.ts, git_dates.rs
- status
- done
- tests
- idea-timeline.test.ts, idea-timeline.test.ts:upsert preserves analyser git dates and change count across reindex, idea-timeline.test.ts:listIdeaIdsMissingGitDates includes ideas missing change count, webview-table-queries.test.ts:orders by git date and change count columns, ideas-git-columns-perf.test.ts, format-git-date.test.ts, git_dates.rs
ideas_list_git_columns_performance
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Ideas table pages that show git_idea_timeline_analysis columns must read indexed
`git_created_at` / `git_modified_at` / `git_change_count` only — never invoke git or the
`git_dates` analyser on the UI query path.
At ~ 2 k ideas, a 50 - row page ( including sorts by git modified / change count ) must stay
interactive: absolute budgets plus relative guards vs path sort and vs a simulated
per-row git walk. Missing-id backlog queries for background fill must also stay fast
once the index is filled.
Implemented by sqlite-store.ts
( `listIdeasPage`, `listIdeaIdsMissingGitDates` ).
ideas_list
git_idea_timeline_analysis
- status
- done
- tests
- ideas-git-columns-perf.test.ts, ideas-git-columns-perf.test.ts:listIdeasPage reads indexed git columns without running the analyser, ideas-git-columns-perf.test.ts:indexed git page load stays interactive and under simulated git-per-row cost, ideas-git-columns-perf.test.ts:listIdeaIdsMissingGitDates stays fast on a large filled index, ideas-git-columns-perf.test.ts:git change-count sort page stays within absolute budget
ideas_list_git_date_format
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
First committed / last modified cells in ideas_list must display a stable `YYYY-MM-DD`
authored calendar date from indexed git `%aI` timestamps ( not locale-dependent
`toLocaleDateString`, and not raw ISO / patch junk ).
Invalid, empty, or non-date values render as an em dash ( `—` ).
The `git_dates` analyser must only persist ISO author-date lines so patch hunks never
become stored " dates ".
Implemented by format-git-date.ts
and git_dates.rs ( `parseGitAuthorDates` ).
ideas_list_git_date_format
git_idea_timeline_analysis
- status
- done
- tests
- format-git-date.test.ts, format-git-date.test.ts:formats git %aI timestamps as YYYY-MM-DD, format-git-date.test.ts:keeps authored calendar day (does not shift across timezone), format-git-date.test.ts:renders empty and invalid values as an em dash, git_dates.rs, git_dates.rs:parses_iso_author_dates_and_ignores_patch_noise
overview_page
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
First tab: a workspace overview for the active base — product-facing copy ( not index / debug jargon ).
- At a glance: idea count, reference count, issues, bases, and a friendly readiness status.
- Coverage: collapsible overview_coverage_scores ( lazy, non-blocking ).
- Search: live cross-surface search over ideas, ideasets, attributes, and references for the active base;
results group by surface with sample hits and actions to open the matching tab with the query applied ( overview_search ).
- Export: buttons that open export_webview with HTML, Markdown, JSON, CSV, or PDF pre-selected ( or the form without a format override ).
- Links: project site, support / email, GitHub.
- Recent index / analyse activity preview ( idea names when available ) with a link to timeline_page
for idea git history — this preview is not a git surface.
- implementation
- OverviewPanel.svelte, ideas-summary-panel.ts
- todo
- deep links into HTML export pages when an export exists
overview_coverage_scores
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Collapsible " Coverage " section on overview_page / OverviewPanel.svelte.
Product-facing metrics for how thoroughly ideas map into the active base's project files
( respecting configuration_rqignore ):
- Linked files: percent of project files ( non-requirement, non-ignored ) that ideas reference —
exact path match after resolve, or under a referenced folder. Show " N of M project files ".
- Requirement density: ideas per thousand lines of eligible project code; also show idea count and line count.
- Linked paths: distinct files or folders referenced from ideas.
- Requirement files: count of requirement documents in the base.
Collapsed by default. Calculate only when the user expands the section ( not on Overview open / tab switch ).
Non-blocking: host work must not stall Overview chrome or other tabs; show a loading state until the result arrives.
When the index is not ready or calculation fails, show a clear message — never fake zero scores.
Recalculate on expand when the active base changes or when the user refreshes; otherwise reuse the last result for the session.
- implementation
- OverviewPanel.svelte, ideas-summary-panel.ts, overview.rs
- status
- done
- test
- overview.rs
overview_search
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Overview search fans out across Ideas, Ideasets, Attributes, and References using the same ui-sql filters as those tabs.
Debounced; returns counts plus a short sample of hits per surface; clicking a hit opens the idea ( or the attribute → Ideas handoff );
" Open in … " applies the search string on that tab.
- implementation
- OverviewPanel.svelte, ideas-summary-panel.ts, webview-table-queries.ts
timeline_page
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Timeline tab shows the evolution of ideas for the active base — not raw file-index noise.
Sources:
- Git idea lifecycle from indexed `git_created_at` / `git_modified_at` ( created + last edited as separate events when they differ )
- Session idea reindex activity ( one event per idea persisted, with name / status / summary when available )
Missing git dates are filled by the silent background indexer
( git_dates / git_dates_background_indexing ) —
opening Timeline must not run git log on the UI path.
Reindex must preserve existing git dates across upsert.
Entries are reverse-chronological, filterable by source ( git / reindexed ), and clickable to open the idea.
Each event surfaces idea-centric info: name, short summary, status, kind / tags, and path.
Full live multi-commit git log browsing remains out of scope; this surfaces indexed idea history first.
- implementation
- TimelinePanel.svelte, ideas-summary-panel.ts, sqlite-store.ts, git_dates.rs, register-git-dates-background.ts, git-dates-background.ts
- status
- done
- tests
- idea-timeline.test.ts, idea-timeline.test.ts:listIdeaIdsMissingGitDates can filter or prefer a file, git-dates-background.test.ts, git-dates-background.test.ts:processes active-file priority ids before the global backlog
bases_tab
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Table of discovered base entries in the workspace ( label, path, ready, idea / edge / issue counts, state ).
Selecting a row pins that base ( pointer swap ) per ideas_summary_base_scope.
Filterable / sortable / column options like other tables; data comes from index status, not a merged cross-base SQLite dump.
Client-side search and column filters via BasesTable.svelte / bases-filter matcher.
- implementation
- BasesTable.svelte, bases-filter.ts
- status
- done
attributes_tab
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Attributes index for the active base, aligned with html_export_attributes_index:
attribute key, idea count, distinct value count, sample values.
Searchable and filterable; clicking a key opens Ideas with that attribute column enabled.
Aggregated in webview-table-queries.ts / sqlite store.
- implementation
- AttributesTable.svelte, webview-table-queries.ts, ideas-summary-panel.ts
idea_sets_tab
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
The idea sets page should list the ideasets
unlike the ideas page, it should not directly to the ideaset, but should have a dropdown to it's items.
the path column should link to the ideaset source.
members should appear as chips with a … control to expand and show all member chips when needed.
per IdeasetsTable.svelte
table_column_filters
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Every data table supports a global search and a per-column filter row ( ColumnFilterRow.svelte ),
matching the usability of html_export_list_views.
Text / path / body columns use searchable inputs; closed sets ( idea kind, reference type, ideaset kind, base ready )
use select / multi-select from a fixed option list.
Typed filter / search text must keep spaces through the host round-trip ( do not trim the echoed query —
SQL matchers may trim only when building LIKE patterns ).
Select filters must support deselect / clear back to " All " ( controlled select value + clear control for multi-select ).
Column filters are applied in the ui-sql layer ( webview-table-queries.ts ) together with existing chip filters.
Table panels must bind AppState query / rows via Svelte 5 `$derived` ( not legacy `$:` ) so filtered results from
the extension message listener re-render — same pattern as graphical_graph / GraphView.
Bases table filters client-side in the webview; other tables round-trip search through ideas-summary-panel.ts.
table_column_options
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Each table has an Options control ( TableOptionsMenu.svelte ) to show or hide columns.
Visibility persists per tab in workspaceState via table-ui-state.ts.
- implementation
- TableOptionsMenu.svelte, table-ui-state.ts, ideas-summary-panel.ts
group_by_type
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Ideas table can group by idea kind ( block / oneliner ).
References table can group by reference type ( file / comment / sub-idea ).
Grouping is a toolbar toggle; rows are ordered by group then the active sort; UI shows collapsible group headers.
- implementation
- IdeasTable.svelte, ReferencesTable.svelte, webview-table-queries.ts
index_panel
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
Last tab: workspace index health — readiness, summary stats, sync progress, errors, refresh / cancel / clear-and-rebuild.
per idea_index_triggers and nonblocking_index
Implemented by IndexPanel.svelte.
index_panel_base_support
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
The index_panel / Ideas Summary chrome supports switching between bases in the workspace.
Switch is a pointer swap per active_base_switch and ideas_summary_base_scope — rebind views, do not sync.
- status
- done
ideas_table_filters
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
the ideas table should support text search, column sorting, and attribute-column filters driven by chip clicks.
attribute filters require a non-null attribute value in sqlite json per webview-table-queries.ts
reference chip filters match outbound / inbound edges by target or source id per webview-table-queries.ts
chips are right-aligned so truncated labels keep the informative suffix visible.
active attribute and reference filters appear as removable chips in the table toolbar.
Also table_column_filters, table_column_options, and group_by_type.
- status
- done
graphical_graph_tab
reqlan rq/extension/workspace-summary/ideas_summary/webview.rq
see graphical_graph
index_cache_reuse
reqlan rq/indexer/cache-reuse.rq
Identify where the ideas index, diagnostics store, or in-process caches already hold
data that other modules recompute.
Goal: one walk, one sync, one open store where possible; reuse SQLite edges and mtime
maps instead of rebuilding graphs from scratch.
Related: nonblocking_index, indexing_incrementality, index_consumers,
index_sequencing.
- status
- draft
already_cached
reqlan rq/indexer/cache-reuse.rq
Mechanisms that already reuse stored state:
- Soft sync mtime skip on documents_table ( nonblocking_index )
- Idle stale check that indexes only dirty paths ( indexing_trigger_auto )
- Git date columns on ideas_table ( no git walk on every UI paint )
- Fuzzy search and paged Ideas Summary SQL over SQLite ( avoid full in-memory dumps when used )
index_cache_reuse
single_sync_walk
reqlan rq/indexer/cache-reuse.rq
One native directory walk records base roots, `.rq` paths, and allowlisted code paths.
The walk does not read file bodies.
Startup, Refresh, and create-base each run that walk once. They do not call `findFiles` and they do not run a second native `syncWorkspace` walk.
Soft sync indexes the path list and skips unchanged mtimes.
Idle stale check stats paths already stored in SQLite. New files arrive from the file watcher.
The language server does not walk. The extension sends the base roots after the scan.
Overlapping callers share one in-flight scan.
CLI and MCP `sync_workspace` uses the same walk ( one pass, stop at nested bases ).
index_cache_reuse
soft_sync
scan_limits
- implementation
- scan.rs, scan-workspace.ts, index-service.ts, workspace-index.ts, session.rs
- status
- done
- tests
- scan.rs:one_walk_returns_bases_rq_and_code_and_skips_ignored_dirs, refresh-rediscovers-bases.test.ts:startup scan does not call findFiles
single_open_store
reqlan rq/indexer/cache-reuse.rq
The extension adapter owns a live workspace-index.ts / SQLite connection per base.
`getAnalysisApi()` / open-analysis-api.ts must not open a second runtime that re-runs
`ensure_ready` → `sync_workspace` when the adapter already synced.
Reuse the open store for file-context, deprecation, and semantic commands.
index_cache_reuse
extension_ui_consumers
- status
- draft
reuse_sqlite_edges_for_hops
reqlan rq/indexer/cache-reuse.rq
Activity bar and Ideas Summary already query hop neighbourhoods from SQLite edges.
Language-server reference ranking ( reference_code_completion_sequencing ) rebuilds
adjacency from open Langium documents in reqlan-completion-provider.ts.
When the index is ready, completion hop ranking should prefer indexed edges
( or a shared hop API ) over a second AST-derived graph.
index_cache_reuse
extension_ui_consumers
- status
- draft
path_completion_listing_cache
reqlan rq/indexer/cache-reuse.rq
Import and anonymous file-path completion ( import_code_completion_ranking,
anonymous_reference_code_completion, reference_code_completion_objects ) walk
directories via reqlan-path-completion.ts.
Reuse directory listings across keystrokes ( TTL cache ) so each keystroke does not
re-walk the filesystem; clear the cache in tests and on demand.
index_cache_reuse
- implementation
- reqlan-path-completion.ts
- status
- draft
avoid_full_list_all_ideas
reqlan rq/indexer/cache-reuse.rq
Prefer `fuzzySearch`, paged SQL, or catalog deltas over materialising every idea.
Avoid:
- reference-search / wildcard panels calling `listAllIdeas` when search APIs suffice
- Ideas Summary `sendFullGraph` dumping all ideas and edges ( graphical_graph guidance )
- repeated full-catalog pushes when only a few documents changed
index_cache_reuse
extension_ui_consumers
- status
- draft
unify_inbound_indexes
reqlan rq/indexer/cache-reuse.rq
Inlay hints and code lens must read inbound edges from edges_table,
not Langium IndexManager.
Query: edges whose `target_id` is an idea in the open file, plus `comment_link` /
`file_reference` rows whose `target_file` matches that file.
File-top CodeLens uses the `file_reference` subset
( file_inbound_code_lens ).
The extension host runs the query and pushes a snapshot to the language server.
The language server does not open SQLite ( extension_ui_consumers ).
Updates follow index sync independently of open-file parse
( open_file_reference_sequencing, inbound_snapshot_events ).
Mutation hooks already use the same store. Share one graph.
Related: index_cache_reuse, local_symbolic_analysis,
inbound_inlay_index_performance.
- implementation
- sqlite-store.ts, inbound-file-referencers.ts, reqlan-inlay-hint-provider.ts, reqlan-inbound-reference-inlay-label.ts, reqlan-inbound-snapshot.ts, reqlan-reference-code-lens.ts, reqlan-file-inbound-code-lens.ts, register-inbound-sqlite-sync.ts, inbound-snapshot-push.ts, queries.rs
- status
- done
- tests
- queries.rs:inbound_for_file_returns_edges_targeting_ideas_in_file, queries.rs:inbound_for_file_returns_file_reference_targeting_file, inbound-referencer-index-perf.test.ts:inlay referencers come from the pushed snapshot, not findAllReferences, inbound-file-referencers.test.ts, inbound-snapshot-push.test.ts
inbound_snapshot_events
reqlan rq/indexer/cache-reuse.rq
Host → LSP inbound snapshots are event-driven and incremental.
Push only when the ideas index is ready ( catalog update, ready-edge, visible-editor change, or window focus ).
While Syncing or not ready, do not push an empty batch that clears the language-server last-good map;
set a deferred flag and flush on the next ready event.
The language client often starts before the index — registration must ensure-open / defer, not skip forever.
Each notification is a per-document merge for visible editors; URIs not in the batch stay as last-good until replaced or the document closes.
After a single-file enqueue reaches ready, notify catalog so consumers get a ready-state event
( mid-sync catalog notifies alone are not enough ).
Coalesce concurrent push work so catalog spam drains to one ready pass.
Related: unify_inbound_indexes,
lazy_features_after_outbound,
inbound_inlay_index_performance.
- implementation
- inbound-snapshot-schedule.ts, inbound-snapshot-push.ts, register-inbound-sqlite-sync.ts, workspace-index.ts, reqlan-inbound-snapshot.ts
- status
- done
- tests
- inbound-snapshot-push.test.ts, inbound-snapshot-store.test.ts, workspace-index.test.ts:enqueueIndex notifies catalog when ready
overview_coverage_reuse
reqlan rq/indexer/cache-reuse.rq
Overview coverage must not re-walk the base with `.rqignore` when a soft sync just
produced an equivalent file set.
Reuse the last sync document list or a cheap SQLite documents query.
index_cache_reuse
soft_sync
- status
- draft
index_consumers
reqlan rq/indexer/consumers.rq
Modules that read or write ideas_index_sqlite / index:
- Engine write / read: workspace-index.ts, Rust sync / store under ownership
- Extension adapter: index-service.ts ( watchers, Uri conversion, multi-base )
- Headless: open-analysis-api.ts for cli_package and server.ts
- Activity bar: activity-bar-webview-provider.ts ( ideas-in-file, hop refs, search via fuzzy )
- Ideas Summary: ideas-summary-panel.ts ( table SQL, graph slices, overview )
- Search: fuzzy_search, file_search
- Check / analyse / export: check, analytical export APIs
- Local graph: local_graph_analysis
Product aliases: index_ideas, index_technology, consumption.
Related: index_cache_reuse, index_sequencing.
- implementation
- workspace-index.ts, index-service.ts, open-analysis-api.ts, activity-bar-webview-provider.ts, ideas-summary-panel.ts, server.ts
- status
- done
extension_ui_consumers
reqlan rq/indexer/consumers.rq
VS Code surfaces that query the live ideas store through index-service.ts:
- Activity bar workspace / search / minigraph / todo ( activity-bar-webview-provider.ts )
- Ideas Summary panel ( ideas-summary-panel.ts ) — prefer paged SQL and capped graph queries
- Reference-search and wildcard-match panels ( may call `listAllIdeas`; see avoid_full_list_all_ideas )
- Chat / AI commands that call `getFileContext`, `getLocalGraph`, or semantic search
- Refactor and mutation hooks that read inbound edges from the store
- Name and attribute catalog sync that pushes index rows into the language server
The Rust language server may open the ideas index read-only for rename, find-references, and fallback completion.
Open-file inbound inlays and file CodeLens use the host-pushed snapshot first ( no SQLite in those handlers ).
index_consumers
headless_consumers
reqlan rq/indexer/consumers.rq
CLI and MCP open the same per-base application memory via open-analysis-api.ts / `openAnalysisApi`.
They sync on activate or command ( headless_sync_on_ready ).
They have no file watchers and no idle stale loop.
Shared path rules: application_memory, `REQLAN_INDEX_PATH` when set.
index_consumers
cli_package
server.ts
diagnostics_consumers
reqlan rq/indexer/consumers.rq
Readers of diagnostics_sqlite / index_diagnostics_store:
- Index diagnostics webview ( index-diagnostics-panel.ts / index_diagnostics_webview )
- Soft / hard sync writers that append sync_runs and file_timings
- Ideas Summary timeline / problem list for activity rings and file issues ( Rust schema v2 )
index_consumers
diagnostics_sqlite
reqlan rq/indexer/diagnostics-schema.rq
Per-base timing and index-issue store at `<base>/.reqlan/index-diagnostics.sqlite`
( index_diagnostics_store / application_memory ).
Sibling of ideas_index_sqlite; Clear & rebuild of the ideas index must not delete it.
Authoritative schema lives in Rust ( diagnostics.rs, `DIAGNOSTICS_SCHEMA_VERSION = 2` ).
The TypeScript facade ( index-diagnostics-store.ts ) is thinner and focuses on timing rows.
Related: index_diagnostics_timing, index_diagnostics, index_diagnostics_metrics,
index_diagnostics_webview, sqlite_wal_sidecars, diagnostics_consumers.
- implementation
- diagnostics.rs, index-diagnostics-store.ts
- status
- done
diagnostics_meta_table
reqlan rq/indexer/diagnostics-schema.rq
Table `meta` — `key TEXT PRIMARY KEY`, `value TEXT NOT NULL`.
Stores `schema_version` for diagnostics_sqlite.
sync_runs_table
reqlan rq/indexer/diagnostics-schema.rq
Table `sync_runs` records one soft / hard / idle indexing pass.
Columns include: `id`, `started_at`, `finished_at`, `duration_ms`, `trigger`,
`total_files`, `skipped_mtime`, `indexed_files`, `error_files`, `cancelled`,
`sum_file_duration_ms`, `avg_path_depth`.
Retention keeps the latest 50 runs ( diagnostics.rs `MAX_RETAINED_RUNS` ).
Feeds index_diagnostics_metrics and index_diagnostics_webview.
diagnostics_sqlite
index_triggers
file_timings_table
reqlan rq/indexer/diagnostics-schema.rq
Table `file_timings` stores per-file duration rows for a sync run.
Columns: `id`, `run_id` ( FK → `sync_runs` ), `file_uri`, `duration_ms`, `outcome`, `path_depth`.
Indexes: `idx_file_timings_run`, `idx_file_timings_duration`.
diagnostics_sqlite
index_diagnostics_timing
file_index_issues_table
reqlan rq/indexer/diagnostics-schema.rq
Table `file_index_issues` ( Rust diagnostics schema v2 ) persists parse / extract / persist problems.
Columns: `file_uri`, `line`, `column`, `message`, `phase`, `idea_names`, `cause`, `at`.
Cap: 500 rows. Survives editor restart for Ideas Summary problem lists.
diagnostics_sqlite
activity_ring_tables
reqlan rq/indexer/diagnostics-schema.rq
Rust diagnostics schema v2 also keeps activity rings:
- `document_updates` — Ideas Summary timeline “ index ” events ( `file_uri`, `idea_count`, `ideas`, `at` )
- `workspace_changes` — watcher create / change / delete activity ( `file_uri`, `change`, `at` )
Cap: 50 rows each ( diagnostics.rs `MAX_ACTIVITY` ).
diagnostics_sqlite
definition
reqlan rq/indexer/indexer.rq
The indexer should live in the core.rq module.
On-disk schema: ideas_index_sqlite and diagnostics_sqlite.
Layout and WAL sidecars: reqlan_directory_layout.
Consumers: index_consumers ( extends consumption ).
Sequencing and triggers: index_sequencing ( extends triggers ).
Cache reuse opportunities: index_cache_reuse.
index
reqlan rq/indexer/indexer.rq
The ideas graph indexer: parse `.rq` with the native engine, extract ideas / edges, persist to rusqlite SQLite.
Same-file `member` edges target the member leaf ( references_to_subidea ).
Wildcard path + idea fan-out: wildcard_reference_edges
( wildcard_references ).
Ideas Summary graph can hide those edges via webview.rq /
wildcard_refs_toggle.
Soft mtime sync skips unchanged files. `extract_version` in the ideas index meta is the extract-rule generation. When that number does not match the engine, sync rebuilds so stale edges do not remain ( inline_code ).
Owned by ownership; consumed per consumption.
- tests
- schema.rs:opens_at_schema_version_4, schema.rs:schema_v4_columns_round_trip_git_count_and_mtime, wildcard_reference_edges.rs:sync_persists_wildcard_reference_edges, extract_parity.rs:qualified_ideaset_member_reference_targets_leaf_idea_not_ideaset, broken_references.rs:sync_drops_stale_inline_code_file_refs_when_extract_version_changes
wildcard_reference_edges
reqlan rq/indexer/indexer.rq
Native extract ( `extract.rs` ) expands each AST wildcard
against the idea catalog ( `match_wildcard` / workspace candidate list ).
Persist one edge of kind `wildcard_reference` per matching idea ( label = target idea name );
never emit plain `references` for wildcard forms.
Zero matches → one unresolved edge of the same kind ( `isResolved: false`, label = pattern text ).
Edge ids use `edgeId(source, 'wildcard_reference', targetOrUnresolvedKey)`.
Sync walks sorted `.rq` files and grows the catalog as it goes, so a wildcard file is
expanded against ideas already stored plus files earlier in that walk
( sync.rs ).
Ancestor / reference-chain walks treat `wildcard_reference` like `references`
( sqlite-store.ts ).
Ideas Summary references table groups them under sub-idea with other idea-to-idea links;
graph visibility is webview.rq /
wildcard_refs_toggle.
Soft mtime sync skips unchanged files — after introducing this edge kind, reindex ( or touch )
`.rq` files that contain wildcards so stored rows leave any legacy `references` fan-out.
Langium `idea-extractor` keeps the same kind for remaining TS extract paths.
Open-file local extract ( local_symbolic_analysis ) does not expand wildcards against a catalog.
Related: wildcard_references, index, indexer_rust,
wildcard_refs_toggle,
wildcard_reference_edges.
- implementation
- extract.rs, types.rs, sync.rs, extract.rs, types.ts, sqlite-store.ts, reqlan-wildcard-resolve.ts
- status
- done
- tests
- wildcard_reference_edges.rs, wildcard_reference_edges.rs:expands_wildcard_refs_to_one_edge_per_matching_idea, wildcard_reference_edges.rs:emits_unresolved_edge_when_catalog_has_no_matches, wildcard_reference_edges.rs:stores_wildcard_fan_out_as_wildcard_reference_kind, wildcard_reference_edges.rs:extract_indexed_document_fans_out_edges_for_matching_catalog_ideas, wildcard_reference_edges.rs:sync_persists_wildcard_reference_edges, wildcard_reference_edges.rs:sync_persists_unresolved_wildcard_edge_when_catalog_has_no_matches, wildcard_reference_edges.rs:indexer_and_graphical_graph_rq_capture_wildcard_edge_and_toggle_ideas, wildcard_reference_edges.rs:stores_wildcard_fan_out_as_wildcard_reference_kind, html_export.rs:html_export_workspace_graph_includes_wildcard_refs_chip_and_edges
local_symbolic_analysis
reqlan rq/indexer/indexer.rq
Open-file symbolic analysis must run in Rust on one file only.
Input: file URI plus source text ( and optional import-root mappings ).
Output: ideas in that file, import binding names in that file, outbound edges with UTF-8 source byte spans, and same-file
inbound backlinks ( edges whose target is an idea declared in this file ).
Import binding names let a qualified reference name an import alias
( check_qualified_missing_idea ).
LSP document-link and error underlines must convert those spans to UTF-16
( reference_underline_syntax_align ).
Cross-file inbound still comes from SQLite via unify_inbound_indexes.
Do not read SQLite. Do not walk other workspace documents. Do not load an idea catalog.
The open-buffer model is ast_lifecycle.
The hot path parses this buffer once. It does not run this extract as a second parse.
Import-target confirmation is a separate depth-1 parse
( outbound_one_hop ).
That parse is not this extract.
The language server caches the open buffer by URI plus text fingerprint
( open_file_hot_path ).
Wildcard forms stay one `wildcard_reference` pattern edge ( unresolved ); sync still expands
them later via wildcard_reference_edges.
Flag: `ExtractOptions.local_symbolic` forces an empty candidate list.
CLI: commands `analyse --local-symbolic <file>`.
Sidebar: reference_lists_pane
merges live same-file inbound / outbound with indexed refs ( local_symbolic_sidebar ).
Related: open_file_reference_sequencing, index,
unify_inbound_indexes.
- implementation
- extract.rs, types.rs, lib.rs, parse-source.ts, local-symbolic-references.ts, reqlan-document-link-provider.ts, reqlan-definition-provider.ts, reqlan-local-symbolic-links.ts, reqlan-utf8-lsp-offset.ts, analyse.ts, local-symbolic-context.ts, context-model.ts
- status
- done
- tests
- local_symbolic.rs:analyze_local_symbolic_returns_outbound_without_catalog, local_symbolic.rs:analyze_local_symbolic_ignores_catalog_candidates, local_symbolic.rs:analyze_local_symbolic_includes_same_file_inbound_backlinks, local_symbolic.rs:analyze_local_symbolic_source_offsets_are_utf8_bytes, golden_corpus.rs:qualified_reference_to_an_import_alias_is_not_a_missing_idea, load-native.test.ts:exposes analyzeLocalSymbolic on the engine when present, local-symbolic-references.test.ts, workspace link, local-symbolic-links.test.ts:idea underlines match syntax tokens after non-ASCII text, local-symbolic.test.ts, local-symbolic-context.test.ts
local_symbolic_sidebar
reqlan rq/indexer/indexer.rq
The activity bar reference lists and current-file scope must consume local_symbolic_analysis
for the open buffer text so same-file inbound backlinks and outbound refs appear even when
the SQLite index is stale or not ready.
Merge live local rows with indexed `listReferencesForIdea` / hop-depth rows; dedupe by
direction plus edge id ( and by idea id for scope idea chips ).
Prefer the referencer name as the inbound label ( not the edge target label ).
ownership
reqlan rq/indexer/indexer.rq
The index / indexer lives in `packages/analytical` ( `@reqlan/analytical` ).
Canonical single-base engine: workspace-index.ts ( `WorkspaceIndex` facade ).
Sync / idle impl: workspace-index-sync.ts; one-file parse + persist: workspace-index-file.ts; mtime stale diff: workspace-mtime.ts.
Multi-base registry: one `WorkspaceIndex` per discovered base under application_memory ( `<base>/.reqlan/` ).
Headless entry: open-analysis-api.ts via native-only `openAnalysisApi` ( CLI / MCP ).
On-disk store path: application-memory.ts under `<base>/.reqlan/` — see ownership.
consumption
reqlan rq/indexer/indexer.rq
Consumers of the analytical index:
- extension — thin VS Code adapter index-service.ts ( file watchers, Uri conversion, UI status )
- CLI ( `cli_package.rq".cli_package` ) and MCP — headless open-analysis-api.ts
The extension does not own the indexing engine; it only hosts the adapter.
Module map: index_consumers.
nonblocking_index
reqlan rq/indexer/indexer.rq
Index sync must stay non-blocking for the host UI ( notably activity_bar and workspace_loading ).
Editor startup is gated by first_paint_startup; discovering a base must not construct Langium services, which are initialized lazily on the first parse.
While syncing, surface progress — state, processed / total, and the current file — in workspace_pane and index_panel.
In-flight sync must be cancellable from those surfaces; cancel keeps already-indexed rows and returns the index to ready.
Incremental behaviour ( see also indexing_incrementality ):
- Single-file create / change / delete via watchers indexes only that file — never a full base walk.
- Soft full sync ( `syncWorkspace` / Refresh ) skips parse + persist when the file's mtime matches the value stored on the documents row.
- Hard refresh ( `clearAndRebuildIndex` / Clear & rebuild ) wipes the store and reindexes every file.
- Every sync and stale check applies `.rqignore` to the paths it receives, the same as the base walk; the native single-file index also drops an ignored path.
Thus base discovery cannot make the first sync index ignored files.
Implemented by workspace-index.ts; editor adapter index-service.ts.
- status
- done
- tests
- workspace-index.test.ts, workspace-index.ts, workspace-index.test.ts:soft sync drops rqignored paths supplied by base discovery, sync.rs:soft_sync_skips_unchanged_mtime, sync.rs:hard_rebuild_reindexes_despite_mtime
triggers
reqlan rq/indexer/indexer.rq
Index refresh behaviour:
- indexing_incrementality / nonblocking_index — incremental where possible
- indexing_trigger_filesave / idea_index_triggers — on `.rq` or indexed code-file change
- indexing_trigger_manual — manual reindex commands
- indexing_trigger_open — one soft sync after the activity-bar first-paint gate
- indexing_trigger_auto — idle background mtime staleness check ( cheap; not a full reindex )
Editor watches + idle scheduler: index-service.ts; headless syncs on runtime activate.
Full sequence: index_sequencing.
capabilities
reqlan rq/indexer/indexer.rq
Product capabilities over the index: index_ideas, index_technology, local_graph_analysis,
semantic_analysis, git_dates, completion_tracking, deprecation_impact_analysis,
index_comment_reference_inclusion, and host triggers in graph-analysers.rq.
Indexing performance timing and diagnostic UI: index_diagnostics.
index_ideas
reqlan rq/indexer/indexer.rq
Each base maintains an index of its ideas for fast lookup and navigation ( index ).
The index should update incrementally as. rq files change within that base ( nested child bases excluded ).
Persistence lives in application_memory per base, shared with CLI and MCP — not VS Code extension storage.
Engine ownership: workspace-index.ts in `@reqlan/analytical`; multi-base via BaseRegistry; editor watches via index-service.ts.
index_technology
reqlan rq/indexer/indexer.rq
The index_ideas graph database is rusqlite via the core native engine.
On-disk location is application_memory ( `<base>/.reqlan/ideas-index.sqlite` ), not `context.globalStorageUri`.
Implementation: application-memory.ts, workspace-index.ts, headless open-analysis-api.ts for CLI / MCP, and index-service.ts for the VS Code host.
indexing_incrementality
reqlan rq/indexer/indexer.rq
Indexing should be incremental: watcher-driven single-file updates, and soft full syncs that skip unchanged files by stored mtime.
Hard rebuilds reparse everything. Detail and UX ( progress, cancel, non-blocking UI ): nonblocking_index.
index_comment_reference_inclusion
reqlan rq/indexer/indexer.rq
Comment `rq:…` sites are indexed as `comment_link` edges plus first-class code-file documents, not a separate idea kind.
Graph surfaces them as idea → external file nodes ( same file-node id as outbound file_reference ).
Live editor links still use the comment grammar / resolver; the index path is native index_code_files.
- status
- done
deprecation_impact_analysis
reqlan rq/indexer/indexer.rq
Analyse the impact of deprecated ideas on dependent requirements.
Deprecation analysis should report downstream ideas that reference or depend on deprecated items.
git_dates
reqlan rq/indexer/indexer.rq
Creation and last-modified dates, and change count, for ideas via git history where available.
Values are written into the ideas index by the `git_dates` analyser as a silent background job after
soft-sync / catalog updates ( batched, yielded ) — not triggered by Activity Bar focus, opening Timeline,
or Ideas table load.
Host queue and rate caps: git_dates_background_indexing.
- implementation
- git_dates.rs, sqlite-store.ts
- status
- done
completion_tracking
reqlan rq/indexer/indexer.rq
Track and surface completion, outstanding work, and open issues across the requirement graph.
Completion tracking should derive from @ status, @ tags, and other lifecycle attributes where present.
local_graph_analysis
reqlan rq/indexer/indexer.rq
Provide a function to access a small slice of the graph around a given idea.
semantic_analysis
reqlan rq/indexer/indexer.rq
Search the graph for ideas related to a given idea or ideaset.
index_diagnostics_timing
reqlan rq/indexer/indexer.rq
Soft sync and per-file index paths record durations into the diagnostic index under index_diagnostics_store.
See index_diagnostics_metrics.
Must not block nonblocking_index; recording failures are swallowed / logged by the store and must not fail the sync.
index_code_files
reqlan rq/indexer/indexer.rq
Index non- `.rq` source files that contain comment_reference ( `rq:idea` / `rq:idea` ).
The same directory scan records allowlisted text paths ( respecting `.rqignore`, binary_ignore, commentless_file_ignore, and nested child bases ).
Content reads use that list. They are not a second directory walk. text_prefix_skip skips non-text before a full read.
Binary files stay out unless a negation such as `!*.bin` opts them in.
The walk cheap-filters on `rq:`, and persists matching files as documents plus `comment_link` edges.
Edge shape: source = referenced idea, `target_file` = code file URI, kind `comment_link` ( no synthetic file ideas ).
Reindex of a `.rq` file updates kept ideas in place, so their comment links stay. Deletion of a removed idea cascades to its links.
Code documents are re-linked only when the set of idea names in that `.rq` file changes, because links resolve on names only.
A body edit must not read the code files again.
Watcher + idle stale check cover code documents as well as `.rq` files ( triggers, nonblocking_index ).
Consumers: file_related_requirements, file_search,
html_export_code_reference_pages, Ideas Summary comment-reference rows,
local graph ( idea → external file node ), click_code_file.
See index_comment_reference_inclusion, referenced_files.
- implementation
- comment.rs, sync.rs, store.rs, index-service.ts
- status
- done
- tests
- code_file_index.rs:indexes_comment_references_from_non_rq_files, code_file_index.rs:unqualified_comment_ref_matches_catalog_idea_name, code_file_index.rs:rq_reindex_restores_comment_links, code_file_index.rs:rq_reindex_relinks_code_files_only_when_idea_names_change, code_file_index.rs:index_one_file_drops_an_rqignored_rq_file, code_file_index.rs:skips_binary_comment_files_unless_rqignore_negation, file_context.rs:file_context_includes_indexed_comment_links, fuzzy_search.rs:workspace_index_fuzzy_search_includes_comment_code_files
indexer_rust
reqlan rq/indexer/indexer.rq
The index engine ( parse-for-index → extract → SQLite persist → incremental sync ) should be written in Rust.
Crate: `reqlan-index` over `reqlan-parse` per rust_crate_layout.
Extractor ports extract.rs including wildcard_reference_edges.
Store ports schema v4 ( schema.ts ) via rusqlite; diagnostics live in `index-diagnostics.sqlite` on the same engine.
Sync keeps nonblocking_index: per-file upsert, mtime skip, hard rebuild, cancellable progress.
Not the Langium LSP. Comment-file indexing: index_code_files.
- plan
- goal
Native WorkspaceIndex: same rows and incremental behaviour, no Langium on the index path.
constraints
- Schema v4 rusqlite only (no sql.js fallback) after cutover.
- nonblocking_index and index_diagnostics_timing still apply.
- Wildcard fan-out stays wildcard_reference_edges.
- Extension requires the host-matching core engine `.node` from the per-target VSIX.
steps
1. Rust AST → IdeaRecord / EdgeRecord parity tests against the current extractor.
2. rusqlite store + migrations matching SCHEMA_VERSION 4.
3. Soft/hard sync, mtime skip, cancel, diagnostics.
4. Wire through native_bridge once parse+extract golden tests pass.
open
- Richer per-file timing rows from Rust sync into the diagnostics store. - status
- in-progress
- tests
- extract_parity.rs:indexes_scalar_list_block_and_flag_attribute_values, extract_parity.rs:qualified_ideaset_member_reference_targets_leaf_idea_not_ideaset, golden_corpus.rs:corpus_idea_names_match_langium_extract, schema.rs:opens_at_schema_version_4, sync.rs:soft_sync_skips_unchanged_mtime, wildcard_reference_edges.rs:expands_wildcard_refs_to_one_edge_per_matching_idea, wildcard_reference_edges.rs:sync_persists_wildcard_reference_edges
- todo
- surface per-file timing diagnostics from Rust sync into IndexDiagnosticsStore
index_sequencing
reqlan rq/indexer/sequencing.rq
Describe when the ideas index starts, updates, and idles, and which trigger owns each pass.
Capability aliases live in triggers and idea_index_triggers.
Detail ideas below; keep nonblocking_index and indexing_incrementality as the UX rules.
Related: index_consumers, index_cache_reuse,
documents_table, sync_runs_table.
- implementation
- index-service.ts, workspace-index.ts, open-analysis-api.ts
- status
- done
index_triggers
reqlan rq/indexer/sequencing.rq
Trigger map for index_sequencing:
- indexing_trigger_open — one soft sync after activity-bar first paint / base activate
- indexing_trigger_filesave — watcher create / change / delete on `.rq` and allowlisted code files
- indexing_trigger_manual — Refresh ( soft ) or Clear & rebuild ( hard )
- indexing_trigger_auto — idle mtime stale check; index only dirty paths
Git-dates fill is not an index trigger ( idea_index_triggers ).
Each sync run may record a `trigger` string in sync_runs_table.
extension_startup_sequence
reqlan rq/indexer/sequencing.rq
Extension host order ( first_paint_startup, background_startup ):
1. `activate` registers UI only; it must not await index sync.
2. Activity bar paints → startup gate; language client may start on a short fallback.
3. Index adapter activates after paint ( or a short fallback timer ).
4. One native scan ( single_sync_walk, scan_limits ) records bases and file paths.
Soft soft_sync then runs for the **active** base only ( indexing_trigger_open );
other bases stay closed until pin / focus / file events ( event_driven_base_access ).
5. Install watchers for `.rq` and code globs; watch `.reqlan` marker create / delete for rediscovery
( not SQLite child writes ).
6. Idle timer runs idle_stale_check on already-open bases, then releases unused SQLite artifacts
( release_when_idle ).
index_sequencing
index-service.ts
Open-file editor links follow open_file_algorithm
and must not wait for this crawl.
scan_limits
reqlan rq/indexer/sequencing.rq
The workspace scan has two caps. There is no unlimited setting.
Defaults and clamp bounds are the `scan` object in defaults.json.
`reqlan.scan.maxDepth` uses `defaultMaxDepth`, `minDepth`, and `maxDepthLimit` from that file.
The workspace folder is depth 0. A directory deeper than the cap is not entered.
`reqlan.scan.maxEntries` uses `defaultMaxEntries`, `minEntries`, and `maxEntriesLimit` from that file.
The count is directories plus files visited.
When a cap hits, the walk stops, keeps the partial result, and the editor shows a warning. It does not start another scan to finish.
Refresh uses the same caps.
CLI and MCP use the same defaults.
Built-in ignore also skips `target/` so a Cargo tree does not consume the entry budget.
extension_startup_sequence
single_sync_walk
- implementation
- defaults.json, build.rs, scan.rs, scan-limits.ts, package.json, ignore.rs, rqignore.ts
- status
- done
- tests
- scan.rs:depth_2_does_not_return_a_deeper_base_or_rq, scan.rs:entry_cap_stops_and_reports_truncation, scan-limits.test.ts:clamps depth and entries into the allowed range, scan-limits.test.ts:editor scan settings match defaults.json, sync.rs:default_rqignore_skips_node_modules, base-discovery.test.ts:skips target build trees
soft_sync
reqlan rq/indexer/sequencing.rq
Soft full sync ( `syncWorkspace` / Refresh ) indexes the path list from single_sync_walk.
It skips files whose FS mtime matches documents_table. `mtime_ms`, and upserts changed files only.
Progress and cancel follow nonblocking_index.
Prefer a single walk ( soft_sync ).
Triggers: indexing_trigger_open, indexing_trigger_manual ( Refresh ).
index_sequencing
hard_rebuild
reqlan rq/indexer/sequencing.rq
Hard rebuild ( `clearAndRebuildIndex` / Clear & rebuild ) wipes ideas-index rows and
reindexes every file. It must not delete diagnostics_sqlite.
Trigger: indexing_trigger_manual.
index_sequencing
nonblocking_index
watcher_incremental
reqlan rq/indexer/sequencing.rq
File create / change / delete indexes or deletes that one path only — never a full base walk.
Covers `.rq` sources and allowlisted code files for index_code_files.
Trigger: indexing_trigger_filesave.
index_sequencing
indexing_incrementality
idle_stale_check
reqlan rq/indexer/sequencing.rq
When the editor is idle, use document paths already stored in SQLite ( do not scan the tree ), load mtimes in one SQLite read, compare FS mtimes
in memory, and index only mismatched or new files; drop deleted docs in one batch.
If nothing is stale: no state transition, no progress UI, no parse.
Prefer unfocused windows; cancel if the user becomes active again.
Only bases that are already open participate — idle must not reopen every discovered base
( release_when_idle ).
After the check, release unused SQLite artifacts ( inactive bases always; all bases when unfocused ).
Extension host only — see indexing_trigger_auto.
index_sequencing
- tests
- workspace-index.test.ts, sqlite-artifact-release.test.ts:BaseRegistry releaseArtifacts closes handles but keeps descriptors
headless_sync_on_ready
reqlan rq/indexer/sequencing.rq
CLI and MCP call open-analysis-api.ts `ensure_ready`, which runs a soft soft_sync
from single_sync_walk once before serving commands.
No watchers and no idle loop ( headless_consumers ).
index_sequencing
base_catch_up
reqlan rq/indexer/sequencing.rq
Activating or pinning a base schedules an open + soft sync when that base is not ready.
Nested child bases stay excluded from the parent walk ( index ).
index_sequencing
indexing_trigger_open
reqlan_directory_layout
reqlan rq/indexer/sidecars.rq
Each base owns `<base>/.reqlan/` ( application_memory ).
Contents:
- `ideas-index.sqlite` — ideas_index_sqlite
- `index-diagnostics.sqlite` — diagnostics_sqlite / index_diagnostics_store
- `click-sessions.sqlite` — click_session
- SQLite WAL / SHM / journal sidecars — sqlite_wal_sidecars
- `config.json` — json_siblings / base_configuration
- `.rqignore` — rqignore
- `.gitignore` — base_initialisation_ignore / vcs_ignore_for_stores
- `export_settings.json` — reqlan_directory_layout
Path helpers: application-memory.ts. Override: `REQLAN_INDEX_PATH` for a single store.
- implementation
- application-memory.ts, ignore.rs
- status
- done
sqlite_wal_sidecars
reqlan rq/indexer/sidecars.rq
When a SQLite file opens in WAL mode, the engine may create sibling files next to the DB:
- `ideas-index.sqlite-wal` / `ideas-index.sqlite-shm` / `ideas-index.sqlite-journal`
- `index-diagnostics.sqlite-wal` / `-shm` / `-journal`
- `click-sessions.sqlite-wal` / `-shm` / `-journal`
These are true sidecars of the open database, not separate product stores.
Index walks skip them through rqignore ( `*.sqlite-wal`, `*.sqlite-shm`, `*.sqlite-journal`, and the same suffixes on `.sqlite3`, `.db`, and `.db3` ).
Seeded `.reqlan/.gitignore` must keep `*.sqlite*` artifacts out of VCS
( base_initialisation_ignore, ignore.rs `default_gitignore_file_contents` ).
reqlan_directory_layout
schema_migrations
- status
- done
- tests
- rqignore.test.ts:defaults ignore json, sqlite sidecars, and files without comments, ignore.rs:default_rqignore_skips_files_without_comments_until_negated
json_siblings
reqlan rq/indexer/sidecars.rq
JSON files under `.reqlan/` are application-memory siblings, not SQLite sidecars:
- `config.json` — base import roots and settings ( base_configuration )
- `export_settings.json` — export form defaults for export_webview
They do not hold idea graph rows. Tools must not treat them as index cache.
reqlan_directory_layout
vcs_ignore_for_stores
reqlan rq/indexer/sidecars.rq
New bases seed `.reqlan/.gitignore` so SQLite databases and their WAL / SHM / journal
sidecars stay out of version control ( base_initialisation_ignore ).
`.rqignore` is separate: it filters discovery / index walks, not VCS ( rqignore ).
sqlite_wal_sidecars
reqlan_directory_layout
- implementation
- ignore.rs, application-memory.ts
ideas_index_sqlite
reqlan rq/indexer/sqlite-schema.rq
The ideas graph for one base_ownership lives at `<base>/.reqlan/ideas-index.sqlite`
under application_memory.
Schema version is in ( `SCHEMA_VERSION` in schema.ts and schema.rs ).
Runtime migrate runs in Rust ( store.rs ); TypeScript opens the store and calls
native migrate ( sqlite-store.ts ).
Keep schema.ts aligned with schema.rs.
Related: index, indexer_rust, ownership, sqlite_wal_sidecars,
diagnostics_sqlite, index_consumers.
- implementation
- schema.ts, schema.rs, store.rs, sqlite-store.ts
- status
- done
- tests
- schema.rs:opens_at_schema_version_4, schema.rs:schema_v4_columns_round_trip_git_count_and_mtime, schema-v4-roundtrip.test.ts
meta_table
reqlan rq/indexer/sqlite-schema.rq
Table `meta` holds key / value rows ( `key TEXT PRIMARY KEY`, `value TEXT NOT NULL` ).
Known keys:
- `schema_version` — string form of ideas_index_sqlite version ( `"4"` ).
- `extract_version` — extract-rule generation from the native engine.
When it does not match the running engine, soft sync rebuilds so stale edges do not remain
( index, inline_code ).
ideas_index_sqlite
ideas_table
reqlan rq/indexer/sqlite-schema.rq
Table `ideas` stores one row per idea, one-liner, or ideaset.
Columns:
- `id` TEXT PRIMARY KEY
- `name` TEXT NOT NULL
- `kind` TEXT NOT NULL — `block` | `oneliner` | `ideaset` ( types.rs )
- `file_uri` TEXT NOT NULL — path relative to the owning base root
- `line_start` / `line_end` INTEGER NOT NULL
- `summary` TEXT NOT NULL
- `attributes_json` TEXT NOT NULL DEFAULT `'{}'`
- `content_hash` TEXT NOT NULL
- `git_created_at` / `git_modified_at` TEXT nullable
- `git_change_count` INTEGER nullable ( schema v4 )
Indexes: `idx_ideas_file(file_uri)`, `idx_ideas_name(name)`.
ideas_index_sqlite
git_dates_background_indexing
edges_table
reqlan rq/indexer/sqlite-schema.rq
Table `edges` stores directed links in the ideas graph.
Columns:
- `id` TEXT PRIMARY KEY
- `source_id` TEXT NOT NULL — FOREIGN KEY → `ideas(id)` ON DELETE CASCADE
- `target_id` TEXT nullable — idea target when resolved
- `target_file` TEXT nullable — file target ( for example comment links )
- `kind` TEXT NOT NULL — see edge_kinds
- `label` TEXT nullable
- `source_line` INTEGER ( schema v2 )
- `snippet` TEXT ( schema v2 )
- `is_resolved` INTEGER NOT NULL DEFAULT 1 ( schema v2 )
Indexes: `idx_edges_source`, `idx_edges_target`, `idx_edges_target_file`.
ideas_index_sqlite
wildcard_reference_edges
index_code_files
- tests
- linking.test.ts:sqlite-schema quoted path reaches indexer ideas that are not from-imported
edge_kinds
reqlan rq/indexer/sqlite-schema.rq
Persisted edge `kind` values ( types.rs / analytical `EdgeKind` ):
- `references` — idea → idea bracket or wiki reference
- `wildcard_reference` — one row per wildcard match ( or one unresolved row )
- `file_reference` — idea → file path reference
- `ideaset_member` — ideaset → member idea
- `import` — import relationship
- `comment_link` — idea ← code-file `rq:` comment ( index_code_files )
edges_table
documents_table
reqlan rq/indexer/sqlite-schema.rq
Table `documents` tracks which files the indexer has seen.
Columns:
- `file_uri` TEXT PRIMARY KEY — base-relative path
- `content_hash` TEXT NOT NULL
- `indexed_at` TEXT NOT NULL
- `mtime_ms` REAL ( schema v3 ) — soft sync skip when FS mtime matches
Soft sync and idle stale checks use this table
( soft_sync, idle_stale_check ).
ideas_index_sqlite
schema_migrations
reqlan rq/indexer/sqlite-schema.rq
Base tables use `CREATE … IF NOT EXISTS` ( schema.ts `BASE_MIGRATIONS` / schema.rs ).
Versioned upgrades run `(current+1)..=SCHEMA_VERSION`:
- v2 — edge `source_line`, `snippet`, `is_resolved`
- v3 — document `mtime_ms`
- v4 — idea `git_change_count`
Duplicate-column errors on ALTER are ignored so re-open is safe.
Fresh databases create full v4 columns, then set `schema_version` to 4.
Open pragmas: `foreign_keys=ON`, `journal_mode=WAL` ( sqlite_wal_sidecars ).
ideas_index_sqlite
_file
reqlan rq/ingest/ingest.rq
- This file is used for preingestion of ideas into the graph
- It is for ideas that are being drafted, haven't been placed, haven't been linked or represent a significant superseding descructive change to the graph
- i. e. requiring careful integration to leave no trace of deprecated ideas, leave no duplication and leave no conflicts
- ingestion must pass validation via `pnpm run val` ( pnpm_val: check, test, build )
- ingestion requires reqiurement integration into the graph, followed by actual implementation if requested.
attribute_namespaceing
reqlan rq/ingest/ingest.rq
an idea's attributes should be referenceable in links.
an idea should be able to access `example`
Links should link appropriately the parser, lexer,... extension, html...
- example
- my subidea
- implementation
- true
- todo
- true
code-comment-syntax-errors
reqlan rq/ingest/ingest.rq
any time a comment line contains `rq:*`, or common patterns it should be parsed, and be considered in `reqlan check`...
- todo
- true
idea-leading-whitespace
reqlan rq/ingest/ingest.rq
Block ideas often have leading whitespace
The base level should be decided by the first line, subsequent lines should not be fully trimmed
THis line has 4 spaces ( same as first line ). It should parse with no leading whitespace
This line has 8 spaces ( 4 more than first line ) it should parse with 4 spaces as part of the content.
- implementation
- true
- tests
- true
- todo
- true
html-export-changes
reqlan rq/ingest/ingest.rq
The print page should be aware of the idea-leading-whitespace
- todo
- true
empty-attributes
reqlan rq/ingest/ingest.rq
it should be perfectly acceptable to have empty attributes
e. g.:
This should not break the parsing of the file. ( Including in extension errors as well as parser / lexer / tokenizer errors )
- todo
- true
reqlan-check-glob-patterns
reqlan rq/ingest/ingest.rq
When running `reqlan check` it should be possible to specify - - glob patterns to check specific files.
It should be possible to specify multiple glob patterns.
If the targets are outside of the glob, they should be checked, but, not recursively.
- tests
- true
- todo
- true
idea-tooltip-file-link-accuracy
reqlan rq/ingest/ingest.rq
Superseded by traceable_inlay_hints:
inbound inlay label `location` and tooltip targets both use the shared goto / document-link URI builder.
- deprecated
- traceable_inlay_hints
- status
- done
code-action-duplication
reqlan rq/ingest/ingest.rq
I don't know why, but sometimes, the code action drop down duplicates options until there are many.
Without just truncating or deduplicating, resolve the explosion.
- bug
- true
attribute_configuration
reqlan rq/language/attributes.rq
The extension should be largely unopinionated about attributes, allowing users to extend as they see fit.
attributes should be as slim as possible to allow for minimised bloat.
import_keywords
reqlan rq/language/imports.rq
The keywords import, from, and as are reserved for import statements.
Import keywords may also appear as ordinary words in idea body text when not at statement start.
import_from
reqlan rq/language/imports.rq
From-import syntax uses from, a quoted path, import, and an idea name.
From-import may list more than one idea. Separate the names with commas.
From-import may include an alias using as.
The parser records a span for the path, each idea name, and each alias.
Each of those tokens is its own document link.
The path links to the file.
An idea name links to that declaration.
An alias links to the same declaration.
When the alias contains the imported idea name, Ctrl + click on a bracket reference still treats the whole alias as one link.
See aliased_from_import_ctrl_click.
The language server uses the parser spans: language_server_rust.
- example
- ```
from "@/links-to-file.rq" import ishouldlink, ishouldbeasecondlink as ishouldbeathirdvalidlink
``` - implementation
- parser.rs, ast.rs, analysis.rs
- tests
- parsing.test.ts:parses from-import example line inside an attribute block value, local-symbolic-links.test.ts:aliased from-import whose name contains the imported idea is one link, parser.rs:from_import_records_each_token_span, parity.rs:from_import_tokens_link_independently
import_error_recovery
reqlan rq/language/imports.rq
A malformed import must not invalidate the rest of the file.
Recoverable invalid `from` shapes parse as local import nodes with a line-level diagnostic:
- `from "path" as alias` ( mistaken namespace form ) — suggest `import "path" as alias` or `from "path" import <idea>`
- bare `from "path"` — require the `import <idea>` clause
- `from` without a quoted path — consume the remainder of the line as an invalid import
Later imports and top-level ideas continue to parse and link normally.
Same recovery posture for nameless top-level braces: no_name_idea_safe_warning.
If lex / parse never completes, see parse_budget_timeout.
- implementation
- reqlan.langium, reqlan-validator.ts
- tests
- parsing.test.ts:malformed from-as import keeps later ideas parseable, validating.test.ts:reports local diagnostic for from-as mistaken import, validating.test.ts:reports local diagnostic for unquoted from-import
import_namespace
reqlan rq/language/imports.rq
Namespace import syntax uses import and a quoted path.
Namespace import may include an alias using as.
A bracket reference to the alias alone — for example `context_model` — opens the imported file and links only the alias name, like an ideaset namespace.
Qualified references through the alias — for example `builder` — resolve ideas from the imported module.
A qualified reference may also name an import alias bound in that module.
Example: `analysis_runtime` when `analysis_runtime` is an import alias in the imported file.
That name is not an idea. Check does not report it as a missing idea ( check_qualified_missing_idea ).
A from-import of that alias is still a missing idea.
- tests
- linking.test.ts:resolve namespace import references to files, linking.test.ts:namespace import bracket reference links only the alias name, golden_corpus.rs:qualified_reference_to_an_import_alias_is_not_a_missing_idea, parity.rs:golden_corpus_import_alias_is_not_an_unresolved_idea
import_qualified
reqlan rq/language/imports.rq
Qualified import syntax uses import, a quoted path, a dot, an ideaset name, a dot, and an idea name.
Qualified import may include an alias using as.
import_paths
reqlan rq/language/imports.rq
Import path strings may use relative paths such as. / exampleimport. rq.
Import path strings may use paths containing folders.
The import target may be a file or a folder; see import_folder_targets.
Import path strings may use remote urls such as https://company.com/reqs/style.rq.
Import path strings may use an import-root alias shorthand such as `@/path/relative/to/import/root`; see configuration_import_root_alias.
Path forms apply to from-import, namespace import, qualified import, file references, and qualified comment references ( `rq:idea` ); see import_from, import_namespace, import_qualified, reference_file, and comment_reference_import_root_alias.
Editor completion for path strings is covered by code_completion.
configuration_import_root_alias
reqlan rq/language/imports.rq
An import path may start with an alias string, then `/`, then a relative path under that alias's import-root directory.
Default alias string: `@`, written as `@/` plus a path relative to the import root.
Default import-root directory: the workspace folder that contains the `.rq` file ( not the document directory ).
The path after `/` is joined to that alias's import-root directory; the alias itself must be followed by `/` ( e. g. `@reqs` is not aliased ).
Alias strings and import-root directories are configured as configuration_import_roots in the applying `.reqlan/config.json` from configuration_location.
A configured relative `root` resolves against the base root ( parent of `.reqlan` ); an omitted `root` keeps the workspace-folder default.
When several configured aliases could match a path, the longest alias wins.
Related path forms: import_paths, comment_reference_import_root_alias. Completion: code_completion.
File references and the language server use the same locate rule as check: load `importRoots` from the applying `.reqlan/config.json` for the source file ( configuration_location ), then `resolve_rq_path` and join the workspace when the result is relative — including paths with spaces such as `my file.ts`.
- example
- //rq-ignore-error
`from "@/path/relative/to/import/root.rq" import idea` - implementation
- reqlan-path-resolve.ts, file-path-rewrite.ts, reqlan-completion-provider.ts, reqlan-path-completion.ts, reqlan-comment-diagnostics.ts, register-comment-reference-links.ts, path.rs, path_resolve.rs, broken.rs, sync.rs, comment.rs, analysis.rs, session.rs
- tests
- path-resolve.test.ts:resolves import-root alias against the workspace folder, path-resolve.test.ts:leaves non-aliased relative paths document-relative, path-resolve.test.ts:matchImportRootAlias requires alias then slash, path-resolve.test.ts:loads importRoots list from nearest base config, path-resolve.test.ts:resolves using config importRoots mapping, path-resolve.test.ts:rewrite leaves aliased paths unchanged, completion.test.ts:completes import-root alias paths, config.test.ts:multiple importRoots map aliases to different roots, config.test.ts:longest alias wins when mappings overlap, config.test.ts:aliased path uses relative root from applying config, config.test.ts:aliased path uses workspace folder when root is omitted, path.rs:match_import_root_alias_requires_alias_then_slash, path.rs:resolves_default_alias_against_workspace_folder, path_resolve.rs:locate_aliased_file_ref_joins_workspace_root, path_resolve.rs:locate_uses_import_roots_from_applying_config, broken_references.rs:check_accepts_import_root_alias_file_refs, broken_references.rs:check_honours_import_roots_from_applying_config, parity.rs:import_root_alias_file_refs_match_check, parity.rs:import_root_config_file_refs_match_check, comment-reference-resolution.test.ts:creates a document link for an import-root aliased comment reference, comment.rs:resolves_aliased_qualified_comment_path
anonymous_imports_allowed
reqlan rq/language/imports.rq
A quoted path plus idea — for example `attribute` — opens that file as an ideaset.
Every idea in the target file is in scope for that reference.
A from-import or qualified import of the same path only binds the listed names for bare `name` references.
It must not hide other ideas from a quoted-path reference.
- implementation
- reqlan-scope.ts, reqlan-linker.ts
- status
- done
- tests
- linking.test.ts:resolve anonymous import in bracket reference without import statement, linking.test.ts:quoted-path qualified idea is not limited to from-import specifiers, linking.test.ts:quoted-path qualified idea is not limited to a qualified import of the same file, linking.test.ts:sqlite-schema quoted path reaches indexer ideas that are not from-imported
import_tokenisation
reqlan rq/language/imports.rq
if an import is given an alias, then the base name is still available as a variable name and should not cause a conflict.
Only the alias binds in the importing file; the imported idea's base name may be reused for a local idea.
e. g.
The same rule applies to qualified imports with `as`.
Unaliased imports still bind the idea name and conflict with a local idea of that name.
Related: sensible_alias_support.
- implementation
- reqlan.langium, reqlan-import-bindings.ts, reqlan-validator.ts, reqlan-scope.ts
- tests
- validating.test.ts:allows local idea when import uses an alias, validating.test.ts:allows local idea when qualified import uses an alias, validating.test.ts:reports duplicate when local idea shares unaliased import binding, linking.test.ts:import idea reference resolves to imported file when local idea shares name
wildcard_references
reqlan rq/language/imports.rq
Qualified path + idea-pattern references match multiple ideas across files.
Surface forms: bracket `…` and wikilink `…` ( same `WildcardReference` target ).
Path is a quoted string that may include shell-style globs ( `*`, `**`, `?` ) and `@/` import-root aliases
( configuration_import_root_alias ). Relative globs resolve against the defining document directory;
`.` / `..` segments are collapsed before matching.
Idea pattern is an unquoted `WILDCARD_NAME` that must contain at least one `*` or `?`
Exact quoted-path plus idea stays reference_qualified.
Matching uses anchored globs ( not full JS regex ): path `*` is one segment, `**` crosses segments;
idea `*` / `?` match within the idea name.
Zero matches produce a warning diagnostic. One match also produces a warning — a wildcard is for many ideas;
use a concrete reference_qualified when only one idea matches
( check_wildcard_one ).
Path segment `/**/` must not be lexed as an empty block comment — see comments.
Lexer note: `ID` is a prefix of many wildcard names ( `import_` vs `import_*` ); the token builder
sets `ID.LONGER_ALT = WILDCARD_NAME` so `import_*` is one token. Body prose `*` tokens are accepted
via `WILDCARD_NAME` in PlainText so ordinary `*` characters still parse.
Without that longer-alt, a live wildcard inside a block body can fail Idea recovery and leave later
top-level ideas unindexed ( soft mtime sync will not rebuild until the `.rq` file changes ).
Navigation does not emit N LocationLinks. A document-link click opens
`reqlan.openWildcardReference` with `{ pathPattern, ideaPattern, fromUri }` ( see wildcard_references_webview ).
Go-to-definition does not open that panel.
Indexing fans out per wildcard_reference_edges
( owned under index ): native extract writes one `wildcard_reference`
edge per catalog match; empty catalog / zero matches → one unresolved edge of that kind
labeled with the pattern text. check handles 0 - match and 1 - match fan-out
through check_wildcard_zero and check_wildcard_one
( check_wildcard_sparse ).
Ideas Summary graph toggles those edges via
wildcard_refs_toggle.
The server can answer `reqlan/wildcardReferenceAt`. Go-to-definition does not call it.
Related: reference_embedding, reference_brackets, reference_wikilink,
wildcard_reference_edges, check_wildcard_sparse,
check_wildcard_zero, check_wildcard_one.
Illustrative forms ( fenced so this file does not embed live wildcards ):
- implementation
- reqlan.langium, reqlan-wildcard-resolve.ts, reqlan-token-builder.ts, reqlan-validator.ts, reqlan-file-link-resolver.ts, reqlan-definition-provider.ts, reqlan-document-link-provider.ts, extract.rs, sync.rs, extract.rs, workspace-index-file.ts, main.ts
- status
- done
- tests
- wildcard-references.test.ts, wildcard-references.test.ts:e2e: tokenize → parse → resolve → document link → definition → command args, wildcard-references.test.ts:e2e: ** path glob matches nested fixture files, wildcard-references.test.ts:e2e: imports.rq captures wildcard ideas with status and implementation, wildcard_reference_edges.rs, wildcard_reference_edges.rs:expands_wildcard_refs_to_one_edge_per_matching_idea, wildcard_reference_edges.rs:stores_wildcard_fan_out_as_wildcard_reference_kind, wildcard_reference_edges.rs:extract_indexed_document_fans_out_edges_for_matching_catalog_ideas, wildcard_reference_edges.rs:nested_path_glob_matches_catalog_ideas, wildcard_reference_edges.rs:imports_rq_extract_includes_webview_and_path_filter_ideas, wildcard_reference_edges.rs:indexer_and_graphical_graph_rq_capture_wildcard_edge_and_toggle_ideas, wildcard_reference_edges.rs:sync_persists_wildcard_reference_edges, wildcard_reference_edges.rs:stores_wildcard_fan_out_as_wildcard_reference_kind
wildcard_references_webview
reqlan rq/language/imports.rq
A click on the command document link for a wildcard_references target
runs `reqlan.openWildcardReference` and opens a dedicated **wildcard matches** webview
( beside the editor ) that lists:
- Stats: matching idea count, distinct file count, and @ status breakdown
- Requirements: each matching idea with name, status, path, and summary ( click opens the idea )
- Files: each matching file with idea count ( click opens the file )
Secondary action **Open in Search** seeds the activity-bar
search_pane_seed via `focusIdeaSearch` with:
- `query`: idea pattern with glob meta softened for fuzzy search ( `import_*` → `import` )
- `pathFilter`: the path glob as a hard AND filter ( idea_path_filter )
Payload builder: `buildWildcardMatchesPayload` filters the index catalog by idea glob + path filter.
Protocol for the matches panel is inline host ↔ webview ( `init` / `openIdea` / `openFile` / `openSearch` ).
The document-link target is the command URI. Go-to-definition does not open the panel.
Highlighting of the source reference must stay link-styled — see
syntax_highlighting and
wildcard_reference_highlighting.
- implementation
- register-wildcard-reference-handling.ts, wildcard-matches-panel.ts, main.ts, wildcard-matches-payload.ts, idea-path-filter.ts, activity-bar-messages.ts, app.svelte.ts, package.json
- status
- done
- tests
- wildcard-reference-open-search.test.ts, wildcard-reference-open-search.test.ts:e2e: buildWildcardMatchesPayload lists stats, ideas, and files, wildcard-reference-open-search.test.ts:e2e: wildcardSearchSeed maps command args to focusIdeaSearch payload, wildcard-reference-open-search.test.ts:e2e: command args → seed → pathFilter gates search hits, wildcard-references.test.ts:e2e: tokenize → parse → resolve → document link → definition → command args, textmate-wildcard-highlight.test.ts, semantic-tokens-wildcard.test.ts
idea_path_filter
reqlan rq/language/imports.rq
Shared path-filter helper for wildcard_references_webview search seeding.
Glob or substring match against workspace-relative path and file URI; leading `./` / `../`
segments are stripped for relative filters; `**/` is implied when the filter has glob meta
but is not already rooted with `**/`.
Used only as a hard AND after fuzzy ranking — it never replaces the idea-name query.
- implementation
- idea-path-filter.ts
- status
- done
- tests
- wildcard-reference-open-search.test.ts, wildcard-reference-open-search.test.ts:e2e: command args → seed → pathFilter gates search hits
lexer_bridge_to_syntax
reqlan rq/language/parser_lexer.rq
The context-sensitive token builder is what makes block_idea and prose braces coexist:
structural `{` / `}` are only those that open or close ideas, while nested_curly_braces stay body text.
context_sensitive_lexer_scaling is the performance contract for that bridge; code_snippets is the opacity contract so fence interiors never feed the brace timeline.
Index-path Rust port: lexer_rust / parser_rust.
recovery_vs_budget
reqlan rq/language/parser_lexer.rq
no_name_idea_safe_warning and import_error_recovery keep a *finished* parse usable after local mistakes.
They do not help when lex / parse never returns — that failure mode is parse_budget_timeout.
Workspace load still isolates per-document throws so one bad file cannot abort LSP init; the budget turns non-termination into the same “ leave this file unloaded ” outcome, with diagnostics.
parse_budget_timeout
reqlan rq/language/parser_lexer.rq
Lexing, parsing, or a parse subprocess for a single `.rq` file must finish within `parseBudgetMs` from defaults.json.
If it cannot, do not hang the language server or block the rest of the workspace.
Surface both a warning ( budget exceeded; semantic features may be incomplete ) and an error ( file left unloaded ) on that document, then continue with other files.
Happy path stays in-process ( sync ) for typical file sizes so edits and workspace load stay fast.
Killable worker enforcement is used when the input is large, a file previously hit the budget ( sticky escalate ), or a caller forces the worker path; sync throws still become the same incomplete result shape.
The open buffer stores that result as an empty model plus diagnostics
( ast_lifecycle ).
- implementation
- defaults.json, reqlan-parse-budget.ts, reqlan-async-parser.ts, reqlan-parse-worker.ts, reqlan-document-factory.ts, reqlan-module.ts, reqlan-workspace-manager.ts
- status
- done
- tests
- parse-budget.test.ts:times out a hung parse worker with warning and error, parse-budget.test.ts:returns incomplete result when worker parse fails, parse-budget.test.ts:parses a normal file within budget, parse-budget.test.ts:parses small files on the calling thread without a worker, parse-budget.test.ts:escalates large files to the worker path, parse-budget.test.ts:forceWorker escalates a small file, ast-lifecycle.test.ts:incomplete parse stores an empty model, parser.rs:times_out_hang_sentinel
nested_curly_braces
reqlan rq/language/syntax-edge-cases.rq
if there is a prose block containing curly braces, { such as this one } they should be treated as part of the prose.
Matching braces that end a line — including adjacent pairs like { { SITE_URL } } — stay in the body; they must not close the enclosing idea.
A lone `}` on its own line still closes the structural block so an unbalanced prose `{` cannot swallow the idea closer.
- implementation
- reqlan-token-builder.ts
- tests
- parsing.test.ts:keeps inline prose brace pairs as text, parsing.test.ts:keeps end-of-line matching prose braces as text, parsing.test.ts:parse thanks-for-installing template, parser.rs:keeps_inline_prose_braces, parser.rs:keeps_end_of_line_matching_prose_braces, lexer.rs:prose_braces_stay_other
context_sensitive_lexer_scaling
reqlan rq/language/syntax-edge-cases.rq
Context-sensitive token classification for structural / prose braces and top-level import keywords must remain linear in document size.
The lexer records brace-depth changes sparsely ( not per-character tables ) and looks them up in log time while tokenising, so workspace language-server initialization and editor re-lexes stay bounded.
Code fences are skipped during the brace scan so example braces cannot inflate work or desync depth.
Bounded work still assumes the lexer / parser *returns*; unbounded hangs are cut by parse_budget_timeout.
- implementation
- reqlan-token-builder.ts
- status
- done
- tests
- parsing.test.ts:parses a large import prelude without repeated full-document brace scans, parsing.test.ts:treats fenced TypeScript braces as opaque for surrounding structure
fencing_comments
reqlan rq/language/syntax-edge-cases.rq
A complete same-line fence keeps `//` and `/*` as prose, not comments.
Closed double quotes: " / / this line " contains no comment.
Closed backticks: `//this line` contains no comment.
Closed backticks with a glob: `@reqlan/*` does not open a block comment.
An unclosed backtick is not a fence, so this line `
An unclosed quote is not a fence, so as does "
The Langium lexer, the Rust lexer, comment scanners, and TextMate must use this rule.
Related: comments, inline_code, naked_strings_in_body, comment_span_align.
- implementation
- reqlan-line-fences.ts, reqlan-token-builder.ts, reqlan-comment-resolver.ts, patch-textmate.mjs, reqlan.tmLanguage.json, lexer.rs, rq_ignore.rs
- status
- done
- tests
- parsing.test.ts:parse syntax-edge-cases.rq, comment-in-string.test.ts:isInsideLineFence treats only complete same-line fences as fences, this line in block body is not a line comment, this line in block body is not a line comment, is a line comment, is a line comment, inside complete backtick fences when locating line comments, references.test.ts:findCommentSpansInText treats unclosed fences as comments and closed fences as prose, * inside complete backtick fences, * in block body is not a block comment, * is not a block comment, langium-rust-parse-align.test.ts:fencing_comments, lexer.rs:backticked_slash_star_is_not_a_comment, lexer.rs:quoted_slash_slash_in_body_is_not_a_comment, lexer.rs:backticked_slash_slash_in_body_is_not_a_comment, lexer.rs:unclosed_backtick_then_slash_slash_is_a_comment, lexer.rs:unclosed_quote_then_slash_slash_is_a_comment, rq_ignore.rs:does_not_treat_marker_inside_backticks_as_a_directive
one_liner_curly_brace_context
reqlan rq/language/syntax-edge-cases.rq
this should { be acceptable } as well
closing_nested_curly_braces
reqlan rq/language/syntax-edge-cases.rq
if, for some reason, there is a prose block containing only closing curly braces, they should be escaped and allowed \ } like this.
- bug
- true
- tests
- parsing.test.ts:allows escaped closing brace in body prose, parser.rs:allows_escaped_closing_brace_in_body_prose
- todo
- fix this - it's currently not working as expected. in the
file_suffix
reqlan rq/language/syntax.rq
Reqlan requirement documents use the. rq file suffix.
file_layout
reqlan rq/language/syntax.rq
A file begins with zero or more import statements, followed by top-level ideas and ideasets.
The file forms an implicit ideaset; its name may default to the filename without the suffix.
Front matter syntax is not yet specified.
- status
- incomplete
- tests
- parsing.test.ts:parse syntax.rq, parser.rs:parse_syntax_rq
idea_name
reqlan rq/language/syntax.rq
Idea names are identifiers or double-quoted strings.
Unquoted names follow identifier rules and may use letters, digits, underscores, and dashes, for example myidea, my_idea, or dash-or_underscore_delimited-idea.
Quoted names allow spaces and other characters when wrapped in double quotes.
Idea names must be unique within their ideaset or file.
An idea, one-liner, and ideaset must not share a name in the same file.
Idea names should not use reserved keywords.
- implementation
- reqlan-validator.ts
- tests
- parsing.test.ts:parse dash and underscore delimited idea names, parser.rs:parse_dash_and_underscore_delimited_idea_names, validating.test.ts:reports duplicate when local ideaset shares a local idea name
simple_idea
reqlan rq/language/syntax.rq
A one-liner idea is written as a name followed by unstructured body text on the same line.
A name-only idea is a one-liner with just the name and no body text.
One-liner ideas do not continue onto subsequent lines.
A `{` that is not immediately after the name is body text, not a block opener —
see one_liner_curly_brace_context.
`name {}` and `name {hello}` are block_idea forms, not one-liners.
- tests
- parsing.test.ts:parse name-only ideas without a body, parsing.test.ts:same-line braces after a name parse as a block, extract_parity.rs:one_liner_idea_body_populates_summary, parser.rs:one_liner_body_does_not_continue_on_the_next_line, parser.rs:parses_same_line_blocks_without_swallowing_later_ideas
block_idea
reqlan rq/language/syntax.rq
A block idea is a name followed by curly braces that contain a body and optional attributes.
The opening `{` may share the line with the closing `}` ( `name {}`, `name {hello}` ).
The opening `{` may also sit at the end of the name line, with the closer on a later line.
`{` starts a block only when it is immediately after the name ( optional spaces ).
If other text is between the name and `{`, the line is a simple_idea and the braces are body text.
The first unstructured text in an idea body is the main description when no other body attribute is marked.
- tests
- extract_parity.rs:block_idea_body_populates_summary_from_rich_text_parts, extract_parity.rs:block_idea_body_populates_summary_from_rich_text_parts, parser.rs:parses_block_and_oneliner, parser.rs:parses_same_line_blocks_without_swallowing_later_ideas, parsing.test.ts:same-line braces after a name parse as a block, textmate-idea-highlight.test.ts
main_desription_lists_allowed
reqlan rq/language/syntax.rq
- lists are valid in.
- so this should not raise any error. s
ideaset
reqlan rq/language/syntax.rq
An ideaset is a parenthesized, comma-separated list of idea names.
Ideaset members may be unquoted identifiers or quoted strings.
Ideasets act as namespace containers for ideas, nested ideasets, and references.
A bare bracket reference `ideaset_name` targets the ideaset declaration in the same file per same_file_reference.
A bracket reference `member` targets the member leaf per references_to_subidea.
- example
- simple_idea, block_idea
reference_brackets
reqlan rq/language/syntax.rq
Single-bracket references use square brackets around a target.
Forms include ideaset-only, idea-only, ideaset dot idea, and idea dot attribute targets.
An idea dot attribute target follows attribute_namespacing.
same_file_reference
reqlan rq/language/syntax.rq
reference_brackets and reference_wikilink may target an idea, one-liner, or ideaset in the same file.
The target may be declared before or after the reference. Forward references are valid.
Circular references between declarations in the same file are valid.
Resolution order: reference_resolution_order.
- implementation
- reqlan-scope.ts, reqlan-linker.ts, extract.rs
- tests
- linking.test.ts:resolve same-file bracket reference to local idea, linking.test.ts:resolve forward reference to later idea in the same file, linking.test.ts:resolve circular same-file references, linking.test.ts:resolve ideaset member forward reference, linking.test.ts:resolve forward reference to later ideaset in the same file, linking.test.ts:resolve local ideaset before imports, extract_parity.rs:same_file_forward_reference_is_resolved, extract_parity.rs:same_file_forward_ideaset_reference_is_resolved
reference_resolution_order
reqlan rq/language/syntax.rq
For each `.rq` file, identify the names in local scope, then resolve references.
Sequence:
1. Collect all idea, one-liner, and ideaset declarations in the file. Declaration order does not change which names are in scope.
2. Collect reference candidates in the file.
3. Resolve each candidate against those local declarations.
4. Resolve imports only for candidates that have no local match. Stop import lookup for a candidate when a local match exists.
The language server and the indexer must use this sequence.
Open-file editor underlines follow open_file_reference_sequencing.
Related: same_file_reference, ideaset, import_tokenisation,
local_symbolic_analysis.
- implementation
- reqlan-scope.ts, reqlan.langium, extract.rs
- status
- done
- tests
- linking.test.ts:resolve forward reference to later idea in the same file, linking.test.ts:resolve forward reference to later ideaset in the same file, linking.test.ts:resolve local ideaset before imports, extract_parity.rs:same_file_forward_ideaset_reference_is_resolved
open_file_reference_sequencing
reqlan rq/language/syntax.rq
When the editor opens a `.rq` buffer, reference marks follow
open_file_algorithm.
The open buffer stays file-local ( local_symbolic_analysis ).
Cross-file inbound waits for unify_inbound_indexes
and lazy_features_after_outbound.
- status
- done
reference_wikilink
reqlan rq/language/syntax.rq
Double-bracket wikilinks use doubled square brackets around a target.
Wikilinks may include an obsidian-style alias pipe with a display label after the target.
A bare pipe character in body prose — for example kind: idea | file | selection — is plain text, not wikilink syntax.
- tests
- parsing.test.ts:keeps pipe characters in body prose as text, parsing.test.ts:parse extension context-scope.rq module, linking.test.ts:resolve wikilink to idea declaration in main.rq
reference_qualified
reqlan rq/language/syntax.rq
Cross-file references may qualify an import path or alias with an idea name.
Qualified wikilinks may combine a quoted import path with a dot and idea name.
A quoted path opens the target file as an ideaset ( anonymous_imports_allowed ).
Partial from-import of that path does not restrict which ideas the quoted path can name.
- implementation
- reqlan-scope.ts, reqlan-linker.ts
- tests
- linking.test.ts:resolve import path in qualified wikilink, linking.test.ts:quoted-path qualified idea is not limited to from-import specifiers, linking.test.ts:sqlite-schema quoted path reaches indexer ideas that are not from-imported
reference_file
reqlan rq/language/syntax.rq
References may target arbitrary files, not only. rq files.
File reference syntax uses a bracketed quoted path.
A relative path resolves from the document directory.
When that path climbs with `..` and the file is not there, the same path is tried from each ancestor directory up to the workspace folder.
The document-directory file wins when it exists.
Line or line-range references append `L#n` or `L#n-m` after the path inside the brackets.
Test-name references append `:` and the test title after the path ( for example `./app.test.ts:lists items` ).
The first `:` after the path starts the title; later `:` characters stay in the title ( `e2e: …` ).
`://` and a Windows drive `C:` / `C:/` are part of the path, not a test suffix.
Symbol references append a dot-separated symbol path after the quoted file path.
Quoted body text is not a file reference: reference_edgecase.
- implementation
- reqlan-file-references.ts, reqlan-path-resolve.ts, reqlan-imports.ts, reqlan-comment-resolver.ts, path.rs, reqlan-file-link-resolver.ts, broken.rs
- tests
- references.test.ts:parses L# line suffix from file reference strings, references.test.ts:parses :test name suffix from file reference strings, references.test.ts:keeps colons inside the test name suffix, path.rs:strips_test_name_and_line_suffix, path.rs:test_name_suffix_keeps_colons_in_the_title, broken_references.rs:check_strips_test_name_and_line_suffix_before_file_exists, broken_references.rs:check_accepts_test_names_that_contain_colons_from_nested_rq, linking.test.ts:document links resolve test file references to the matching test, path-resolve.test.ts:a climbing relative path resolves from an ancestor directory, path-resolve.test.ts:a file next to the document wins over an ancestor
reference_url
reqlan rq/language/syntax.rq
A bracket reference may target an unquoted absolute URL ( `scheme://…` ).
Example: `com/`.
The URL is one token; `://` is not a line comment.
Unbracketed URLs in body prose stay text.
Quoted remote paths stay reference_file ( `file.ts` ).
Index and check: url_reference.
- implementation
- reqlan.langium, reqlan-token-builder.ts, lexer.rs, parser.rs, reqlan-file-link-resolver.ts
- status
- done
- tests
- parsing.test.ts:parses bracketed url references, parsing.test.ts:does not parse unbracketed urls as url references, linking.test.ts:url references produce document links and no missing diagnostics, lexer.rs:bracketed_url_is_one_url_token, parser.rs:bracketed_url_is_a_url_reference
string_and_reference_apostrophes
reqlan rq/language/syntax.rq
strings should use double or single apostrophes interchangeably and support backslash escapes.
- plan
- goal
Allow reqlan string literals in imports, idea names, and bracketed file/reference targets to use either double or single quotes with backslash escaping.
constraints
- string_literals documents escaping rules; double-quoted syntax must remain valid.
- reference_file bracketed quoted paths must resolve with either quote style.
- Embedded scanners and comment reference parsing must not treat // inside quoted strings as comments.
steps
1. Extend grammar STRING terminal and shared unquote helper for both quote styles.
2. Update import/path/comment/embedded reference scanners and completion to accept single-quoted literals.
3. Update TextMate highlighting for single-quoted strings.
4. Add parsing and reference-resolution tests for single-quoted paths and idea names.
open questions
- None for initial scope; both quote styles apply everywhere STRING is used. - tests
- references.test.ts:unquotes single-quoted reqlan string literals, parsing.test.ts:parse single-quoted import paths and idea names
reference_embedding
reqlan rq/language/syntax.rq
References may appear inline in description, plan, or other attribute values.
References may be declared explicitly in @ references or implied by mention elsewhere.
Reference kinds include dependency, incompatible with, applies to, and related to.
References may use wildcards and apply to namespaces or ideasets — see
wildcard_references for the qualified path + idea-pattern form.
attribute_marker
reqlan rq/language/syntax.rq
Attributes are introduced with the @ prefix.
Attribute names follow identifier rules.
- required
- true
empty_attribute
reqlan rq/language/syntax.rq
A line that contains only @ is insignificant whitespace.
Spaces or tabs may precede that @.
Spaces or tabs may follow that @.
The lexer consumes that @ as hidden whitespace.
The parser does not build an attribute for that line.
That line does not cause a parser error.
That line does not cause a lexer error.
That line does not cause a tokenizer error.
That line does not cause an extension error.
A flag keeps the form @ name.
A negated flag keeps the form @ name!.
A valued attribute keeps its value after the name.
A syntax error on a different line is still reported.
- implementation
- reqlan-token-builder.ts, reqlan.langium, lexer.rs
- tests
- parsing.test.ts:parses a lone @ without a parser error and keeps later ideas, parsing.test.ts:still reports a syntax error when another line is invalid, validating.test.ts:does not report an extension error for a lone @, lexer.rs:lone_at_is_hidden_whitespace, parser.rs:lone_at_keeps_surrounding_ideas, parser.rs:syntax_error_elsewhere_is_still_reported
attribute_forms
reqlan rq/language/syntax.rq
A bare attribute name after @ denotes a true flag or render keyword.
A negated flag uses a trailing bang after the attribute name.
A valued attribute uses a space after the attribute name followed by a value.
A colon after the attribute name is optional legacy syntax and is not part of the value.
Common attributes include plan, status, priority, criticality, confirmation, owner, log, tags, and references with the @ prefix.
Any custom attribute name is allowed.
- tests
- parsing.test.ts:parses valued attributes without a colon, parsing.test.ts:still accepts optional colon before attribute values, extract_parity.rs:indexes_scalar_list_block_and_flag_attribute_values, extract_parity.rs:indexes_scalar_list_block_and_flag_attribute_values
attribute_location
reqlan rq/language/syntax.rq
Marked attributes must be at the start of a line. @ this_is_not_an_attribute
- tests
- parsing.test.ts:treats mid-line @ as body text and line-start @ as attribute, parsing.test.ts:backslash before @ at line start keeps it as body text, lexer.rs:at_only_at_line_start
- this_is_an_attribute
- true
attribute_values
reqlan rq/language/syntax.rq
Attribute values may be unstructured scalar text on the same line.
Attribute values may be block values in curly braces.
Attribute values may be list values in parentheses.
attribute_namespacing
reqlan rq/language/syntax.rq
A bracket link `attribute` targets one attribute of that idea.
The first name is the idea name.
The second name is the attribute name.
The grammar types that name as an attribute or an idea declaration.
`example` targets the `example` attribute of this idea.
The form `member` still targets an ideaset member.
See references_to_subidea.
The editor opens the attribute when the first name is an idea.
The editor reports an error when that idea has no attribute with the second name.
The link target is only that attribute on that idea.
HTML export uses the same link form.
The export link opens that attribute on the idea page.
See example.
Related: reference_brackets, attribute_marker, html_export_internal_links.
- example
- my subidea
- implementation
- reqlan.langium, lexer.rs, parser.rs, reqlan-scope.ts, reqlan-linker.ts, reqlan-attribute-links.ts, reqlan-references.ts, reqlan-reference-code-lens.ts, reqlan-document-link-provider.ts, reqlan-local-symbolic-links.ts, reqlan-outbound-presentation.ts, reqlan-semantic-token-provider.ts, extract.rs, html_utils.rs, mod.rs
- status
- done
- tests
- linking.test.ts:resolves an idea attribute link to that attribute, linking.test.ts:reports a missing idea attribute and does not open another idea, lexer.rs:bracket_attribute_link_lexes_a_dot_between_two_names, parser.rs:parses_idea_attribute_link_as_qualified_names, extract_parity.rs:idea_attribute_reference_targets_owner_not_a_same_named_idea, html_export.rs:attribute_link_opens_the_attribute_on_the_idea_page
lists
reqlan rq/language/syntax.rq
Parenthesized lists contain newline-separated items.
Each list item is either a one-liner or a nameless block idea in curly braces.
Lists may appear as attribute values and inside block bodies.
Named lists use a label followed by a parenthesized item list; the opening parenthesis must be followed by a newline before the first item.
Nested lists may appear inside block values or as list items; the opening parenthesis must be followed by a newline before the first item.
Inline parentheses in body prose — for example continuous ( " live " ) physics or ( pixelRatio 1, no WebGL ) — are plain text, not lists.
- tests
- parsing.test.ts:parse list items as one-liners and anonymous blocks, parsing.test.ts:keeps inline parentheses in body prose as text, parsing.test.ts:keeps later ideas after nested @slides lists with mid-line @plan braces, parsing.test.ts:parse tutorials.rq nested @slides lists without parser errors, golden_corpus.rs:tutorials_rq_keeps_ideas_after_nested_slides_lists
comments
reqlan rq/language/syntax.rq
Line comments use `//` through end of line ( hidden `SL_COMMENT` ).
Block comments use `/* … */` and may span multiple lines ( hidden `ML_COMMENT` ).
Meta comments on the same line after content are allowed ( `keep this // meta` ).
Comments must not open inside a string / reference-string context:
- Naked body quotes ( naked_strings_in_body ): a quoted slash-slash that is not a comment, quoted urls,
`"../mod/**/*.rq"`.
- Reference / import `STRING` paths ( `…`, `from "…" import …` ) — the lexer consumes the
whole quoted path as one `STRING`, so neither `//` nor `/*` inside the quotes starts a comment.
Example: a file reference whose path text contains slash-slash,
`*.rq".*webview*`.
- URL / path-segment guard: `//` immediately after `:` or `/` is not a line comment.
Same-line fences: fencing_comments — complete `"…"`, `'…'`, and ` ` ` … ` ` ` spans keep `
Unclosed quote or backtick openers are not fences, so `//` after them is a comment.
Comment-range identity across lexer, scanner, and TextMate: comment_span_align.
Multiline / glob clash: the empty block form `/**/` is **not** a comment — it is the recursive
glob segment used in paths such as `../mod/**/*.rq`. A real block comment needs a non-empty body
( `/* note */`, `/*\n note\n*/` ). The token builder rejects length-4 `/**/` matches; comment-span
scanners skip the same sequence so embedded `rq:…` discovery stays aligned.
Related: comment_reference_ignore, string_literals, wildcard_references, comment_span_align.
- implementation
- reqlan-token-builder.ts, reqlan.langium, reqlan-comment-resolver.ts, reqlan-line-fences.ts, patch-textmate.mjs, reqlan.tmLanguage.json
- status
- done
- tests
- comment-in-string.test.ts, glob survives tokenize → parse in prose, naked quotes, and reference STRING, comment-in-string.test.ts:e2e: real block comments still hide body text, tokenizes, parses, and keeps path text, inside string literals when locating line comments, inside complete backtick fences when locating line comments, glob segments, comment-span-align.test.ts:golden corpus C-style comment ranges match lexer, scanner, and TextMate, * in block body is not a block comment, * inside complete backtick fences, ignore-error.test.ts, wildcard-references.test.ts:e2e: ** path glob matches nested fixture files, lexer.rs:url_slashes_are_not_line_comments, lexer.rs:glob_star_star_is_not_a_block_comment, lexer.rs:meta_line_comment_after_content_is_hidden
comment_reference_ignore
reqlan rq/language/syntax.rq
Comment reference ignore syntax uses `//rq-ignore-error`.
Comment reference ignore suppresses diagnostics on the immediately following line.
The language server and the CLI use the same core scanner rq_ignore.rs.
- implementation
- rq_ignore.rs, lib.rs, ignore-error.ts, reqlan-ignore-error.ts, reqlan-comment-diagnostics.ts, main.ts, main.ts, broken.rs, check.ts
- status
- done
- tests
- rq_ignore.rs, broken_references.rs:skips_idea_and_comment_refs_on_rq_ignore_error_lines, ignore-error.test.ts, load-native.test.ts:exposes findRqIgnoreErrorTargetLines on the engine when present, ignore-error.test.ts, check.test.ts
code_snippets
reqlan rq/language/syntax.rq
Idea bodies and block attribute values may embed fenced code blocks delimited by triple backticks.
An opening fence is three backticks as the first non-whitespace characters on a line, optionally followed by a language tag such as python or rq.
A closing fence is three backticks as the first non-whitespace characters on a line.
Three backticks in the middle of a line are prose. They do not open a fence.
Everything between the fences is literal opaque text — it is not parsed as reqlan syntax.
Keywords, imports, attributes, braces, and quotes inside a fence are inert for the parser and may be shown as examples without parse errors.
Fenced blocks may span multiple lines and preserve their inner content verbatim.
Brace-depth tracking must skip fence interiors so example braces cannot desync surrounding structure ( no_name_idea_safe_warning ).
Related: comment_span_align.
- example
- ```python
print("hello")
``` - implementation
- reqlan.langium, reqlan-token-builder.ts, reqlan-line-fences.ts, patch-textmate.mjs, lexer.rs
- tests
- parsing.test.ts:parse code snippet in block idea, parsing.test.ts:parse fenced code block in attribute value, parsing.test.ts:treats fenced rq example as opaque text, parsing.test.ts:treats fenced TypeScript braces as opaque for surrounding structure, parsing.test.ts:keeps later ideas after mid-line triple backticks, parsing.test.ts:parse rust_port.rq keeps ideas after comment_span_align fence prose, parsing.test.ts:parse mid-line triple backticks corpus without swallowing later ideas, references.test.ts:embedded file reference scan ignores fenced code blocks, references.test.ts:findCommentSpansInText does not treat mid-line ``` as a fence, langium-rust-parse-align.test.ts:fenced_file_example, langium-rust-parse-align.test.ts:mid_line_triple_backticks, comment-span-align.test.ts:mid-line triple backticks are not a fence, comment-span-align.test.ts:line-start triple backticks lex as CODE_FENCE and hide inner comments, align.rs:fence_body_is_one_code_snippet_not_inner_refs, align.rs:mid_line_triple_backticks_are_not_a_code_snippet, lexer.rs:mid_line_triple_backticks_are_not_a_code_fence, lexer.rs:line_start_triple_backticks_are_a_code_fence, parser.rs:keeps_ideas_after_mid_line_triple_backticks, broken_references.rs:check_skips_file_refs_inside_inline_code_and_fences, golden_corpus.rs:opaque_file_examples_do_not_extract_inline_or_fenced_paths, golden_corpus.rs:mid_line_triple_backticks_keep_later_ideas
inline_code
reqlan rq/language/syntax.rq
Single-backtick spans ( `…` ) are opaque `INLINE_CODE`. They may show example syntax such as a quoted path plus idea.
The grammar does not parse bracket or file references inside the span.
Check and the language server must not report those examples as unresolved file_reference or idea refs.
Related: code_snippets, comment_span_align.
- implementation
- reqlan.langium, reqlan-embedded-file-references.ts, patch-textmate.mjs, lexer.rs, extract.rs
- status
- done
- tests
- references.test.ts:embedded file reference scan ignores inline code examples, * is not a block comment, references.test.ts:embedded file reference scan ignores site showcase interlock inline example, ignore-error.test.ts:does not report file references inside inline code, parsing.test.ts:does not parse a backticked file-only line range as a bracket reference, langium-rust-parse-align.test.ts:inline_code_file_example, langium-rust-parse-align.test.ts:inline_code_file_only_line_range, align.rs:inline_code_file_example_is_not_a_live_ref, align.rs:inline_code_file_only_line_range_is_not_a_live_ref, lexer.rs:backticked_bracketed_file_ref_is_one_inline_code_token, broken_references.rs:check_skips_file_refs_inside_inline_code_and_fences, extract.rs:embedded_scan_skips_backticked_file_ref_with_line_range, extract.rs:extract_skips_backticked_file_only_ref, extract.rs:site_rq_does_not_index_backticked_interlock_path, broken_references.rs:sync_drops_stale_inline_code_file_refs_when_extract_version_changes, golden_corpus.rs:opaque_file_examples_do_not_extract_inline_or_fenced_paths
comment_reference
reqlan rq/language/syntax.rq
Reqlan references may appear in line comments of arbitrary source files.
Comment reference syntax is `rq:idea` or `rq:idea` ( quoted path, optional extra qualification ).
Qualified paths use the same path forms as imports, including import-root aliases such as `@/` — configuration_import_root_alias, comment_reference_import_root_alias.
Discovery skips quoted strings, including Rust raw strings ( `r#"…"#`, `r##"…"##`, `br#"…"#` ), so `rq:…` text in a string is not a live comment.
Editor language coverage is a blocklist, not an allowlist: comment_reference_language_blocklist.
Indexed as `comment_link` by index_code_files.
Unresolved targets: comment_reference_resolution_error.
Indexer listing: test_references.
Refactors: comment_reference_refactor_support.
- implementation
- comment.rs, reqlan-comment-resolver.ts, reqlan-comment-diagnostics.ts, reqlan-path-resolve.ts, register-comment-reference-links.ts, comment-reference-path-context.ts, comment-reference-languages.ts
- status
- done
- tests
- comment.rs:ignores_rq_inside_strings, comment.rs:ignores_rq_inside_rust_raw_strings, comment.rs:click_rs_fixture_string_is_not_a_comment_ref, comment.rs:still_finds_line_comment_after_a_raw_string, references.test.ts:skips rq tokens inside Rust raw strings, comment-reference-resolution.test.ts:creates a document link for an import-root aliased comment reference, comment.rs:resolves_aliased_qualified_comment_path
comment_reference_resolution_error
reqlan rq/language/syntax.rq
If a comment reference cannot be resolved, show it as an error diagnostic.
Do not create a document link to a missing file ( that underline then raises a generic cannot-find-file editor error ).
Related: comment_reference, comment_reference_ignore, comment_reference, references_in_functional_code_comments.
- implementation
- reqlan-comment-diagnostics.ts, register-comment-reference-links.ts
- status
- done
- tests
- comment-reference-resolution.test.ts, comment-reference-resolution.test.ts:reports an error when a comment reference file does not exist, comment-reference-resolution.test.ts:does not create a document link for a missing comment reference file, comment-reference-resolution.test.ts:creates a document link when the comment reference file and idea exist, comment-reference-resolution.test.ts:reports an error when the comment reference idea is missing from the file, rq-ignore-error, comment-reference-resolution.test.ts:reports a missing comment reference file in a loaded document, comment-reference-resolution.test.ts:reports a missing comment reference idea in a loaded file, comment-reference-resolution.test.ts:accepts a resolved comment reference in a loaded document
string_literals
reqlan rq/language/syntax.rq
String literals in import paths and quoted idea names may use double or single quotes.
Escaped characters inside strings follow standard backslash escaping.
naked_strings_in_body
reqlan rq/language/syntax.rq
Quoted text in idea bodies, attribute values, and list items is plain prose, not a string literal.
Quote characters are preserved in the body text. For example, " Fit to view " in a bullet line is body text.
String literals are reserved for import paths, top-level quoted idea names, and quoted paths inside bracket references.
Quoted path-like body text is not a file_reference: reference_edgecase.
- tests
- parsing.test.ts:keeps naked quoted phrases in block body text, parsing.test.ts:keeps naked quoted phrases in attribute scalar values, parsing.test.ts:keeps single-quoted naked phrases in block body text, parsing.test.ts:keeps naked quoted phrases in one-liner body after the idea name, parsing.test.ts:keeps naked quoted phrases in list items, parsing.test.ts:keeps naked quotes alongside bracket references on one line, parsing.test.ts:does not treat naked quoted path-like prose as an import reference, parsing.test.ts:does not parse unbracketed quoted paths as file references, parsing.test.ts:parses reframe requirement snippets with naked quoted UI labels, parsing.test.ts:parses self-contained ideas with apostrophe contractions in body prose, naked-strings.test.ts, comment-in-string.test.ts:single-quoted URL in block body is naked prose, lexer.rs:unbracketed_quoted_path_in_body_is_not_string, parser.rs:unbracketed_quoted_path_is_not_a_file_reference
markdown_links
reqlan rq/language/syntax.rq
Markdown `label(target)` links are supported; the label is not treated as an idea reference.
Example: testing requirements and the golden corpus.
Related: testing, golden_corpus.
- status
- done
- tests
- parsing.test.ts:parse markdown links without treating label as a reference, parsing.test.ts:parse docs.rq markdown folder link, parsing.test.ts:markdown link labels are not treated as reference prefix context, references.test.ts:parses markdown link label and target from raw link text, references.test.ts:embedded file reference scan ignores markdown link labels
round_brackets
reqlan rq/language/syntax.rq
Round brackets indicate a list of ideas or attributes. Items may be separated by commas or newlines.
Attribute list values may use commas or newlines; see @ example_list_attribute_using_commas and @ example_list_attribute_using_newlines.
Parentheses in body prose — including API call shapes like cytoscape. animate ( { fit, easing: ' ease-out-cubic ' } ) — are plain text, not list syntax.
- example_list_attribute_using_commas
- idea1, idea2, idea3
- example_list_attribute_using_newlines
- idea1, idea2, idea3
- example_list_containing_ideas
- subidea1, subidea2
- tests
- parsing.test.ts:keeps inline parentheses in body prose as text, parsing.test.ts:keeps inline braces in body prose as text, parsing.test.ts:parse extension graph.rq library
subidea1
reqlan rq/language/syntax.rq
hello
subidea2
reqlan rq/language/syntax.rq
hi, i'm a subidea
example_ideaset
reqlan rq/language/syntax.rq
Ideaset (example_ideaset)
references_to_subidea
reqlan rq/language/syntax.rq
It is valid to reference a member of an ideaset as `member`, for example subidea1.
The indexer must record that reference on the namespace leaf node. In this example the leaf is subidea1, not example_ideaset.
Related: reference_brackets, same_file_reference, idea_reference, index.
- implementation
- extract.rs, reqlan.langium, reqlan-scope.ts
- status
- done
- tests
- linking.test.ts:resolve ideaset-qualified bracket reference to member leaf not ideaset, linking.test.ts:resolve ideaset member forward reference, extract_parity.rs:qualified_ideaset_member_reference_targets_leaf_idea_not_ideaset, extract_parity.rs:qualified_namespace_import_reference_targets_leaf_in_imported_file
no_name_idea_safe_warning
reqlan rq/language/syntax.rq
A top-level nameless curly-brace block — `{... }` with no idea name — must not take down the parser or the language server workspace.
Parse the block as a recoverable anonymous top-level element, emit a descriptive warning that a name is required before `{`, and continue so later ideas, imports, and links still work.
Nameless blocks inside parenthesized lists remain valid list items per lists; only top-level nameless blocks warn.
Related recovery posture: import_error_recovery. Block shape: block_idea. Fenced examples must stay opaque per code_snippets so braces inside snippets cannot desync structural depth.
Non-termination ( lex / parse never finishes ) is a different failure mode: parse_budget_timeout.
- implementation
- reqlan.langium, reqlan-token-builder.ts, reqlan-validator.ts, reqlan-workspace-manager.ts
- status
- done
- tests
- parsing.test.ts:parses top-level nameless braces without aborting later ideas, parsing.test.ts:treats fenced TypeScript braces as opaque for surrounding structure, validating.test.ts:warns on top-level nameless braces without invalidating later ideas, parser.rs:parses_top_level_nameless_braces_without_aborting_later_ideas, parser.rs:recovers_nameless_block
dash-or_undersore_delimited-idea
reqlan rq/language/syntax.rq
it should be possible to use dash or underscore delimited idea names.
name_only_ideas_it_should_be_possible_to_use_name_only_ideas_without_a_body
reqlan rq/language/syntax.rq
—
syntax_whitespace
reqlan rq/language/syntax_whitespace.rq
whitespace is not significant in attributes.
this line is not an idea, it is part of the main content attribute attribute
- exampleattribute
- the same goes for attributes in an idea
- perfectly_acceptable_attribute
- to labour the point
idea-leading-whitespace
reqlan rq/language/syntax_whitespace.rq
A block body can have spaces or tabs before the text.
The lexer counts a space and a tab as whitespace.
A tab is one whitespace character.
The parser does not replace a tab with spaces.
The base indent is the whitespace at the start of the first body line.
The first body line is the first line of body text in the block.
The first body line can start after column 0.
The base indent is still the whitespace on that line.
A body line with the same whitespace as the base indent has no leading whitespace in the parsed text.
A body line keeps the whitespace that remains after the base indent.
The parser removes the base indent only when the line starts with that same whitespace.
An attribute on its own line stays an attribute.
Example: the first body line has four spaces.
A later line with four spaces has no leading whitespace.
A later line with eight spaces has four spaces in the parsed text.
This line has the same four spaces as the first body line.
This line has eight spaces.
- implementation
- parser.rs, lexer.rs, reqlan-body-indent.ts
- tests
- parser.rs:relative_dedent_keeps_extra_spaces_on_a_later_body_line, parser.rs:relative_dedent_uses_the_indent_of_a_first_body_line_that_is_not_at_column_0, parser.rs:relative_dedent_keeps_an_extra_tab, parsing.test.ts:keeps extra indent on a later body line, parsing.test.ts:uses the first body line indent when that line is not at column 0, parsing.test.ts:keeps an extra tab on a later body line
markov_chain
reqlan rq/modelling/advanced_analysis.rq
graph traveral should be tracked to inform a markov chain model of the graph.
- idea
- true
centroid_search
reqlan rq/modelling/advanced_analysis.rq
allow user or agent to specify multiple nodes, and then to rank matches by lowest distance.
- idea
- true
search_with_context
reqlan rq/modelling/advanced_analysis.rq
function ( exposed in cli ) that allows user to specify current contex ( set of ideas or ideasets or files ), and a search term, yielding the closest matches, in a context aware way.
Implemented as contextual_search ( `AnalysisApi.searchRequirements` + `reqlan search --context` ).
- status
- done
pagerank
reqlan rq/modelling/advanced_analysis.rq
Search algorithm from google based on the graph structure?
- todo
- true
idea_graph_distance
reqlan rq/modelling/advanced_analysis.rq
allow searches to match based on partial match and exponential decay of distance to to ideas matching the search term.
Used by contextual_search: `finalScore = textScore * 2^(-minHop)` with unreachable floor 8.
- status
- done
katz_centrality
reqlan rq/modelling/advanced_analysis.rq
Score each idea by inbound Katz centrality on the citation graph.
An idea scores higher when important ideas reference it.
The score uses resolved reference edges and wildcard reference edges between ideas.
The analysis package exposes the scores as `katzCentrality()`.
The top score is 1.
A graph with no citation edges gives every idea the score 1.
Search can opt in through katz_search.
HTML export shows the score through html_export_katz_column.
- implementation
- katz.rs, api.rs, native-analysis-api.ts
- status
- done
- tests
- katz.rs:chain_ranks_the_cited_end_highest, katz.rs:graph_with_no_citation_edges_scores_every_idea_at_one, katz.rs:citation_edges_skip_unresolved_and_non_reference_kinds
idea
reqlan rq/ontology.rq
A reqlan core unit is an idea.
Syntax: simple_idea, block_idea.
Grammar: reqlan.langium `Idea` / `OneLinerIdea`; index records: types.ts `IdeaRecord`.
Extract: extract.rs, rust_extract; AST: ast.rs.
Product surface: tabs.ts Ideas tab per ontology_aligned_tabs.
- implementation
- reqlan.langium, types.ts, extract.rs, ast.rs, rust_extract
- status
- done
- tests
- parsing.test.ts:parse ontology.rq ideas, parsing.test.ts:parse one-liner ideas, extract_parity.rs:block_idea_body_populates_summary_from_rich_text_parts, extract_parity.rs:block_idea_body_populates_summary_from_rich_text_parts, extract_parity.rs:one_liner_idea_body_populates_summary
ideaset
reqlan rq/ontology.rq
Ideasets are namespace containers for ideas.
Syntax: ideaset. Grammar: reqlan.langium `IdeaSet`.
Index kind `ideaset` plus `ideaset_member` edges: types.ts, extract.rs, types.rs.
A file is an implicit ideaset ( file_layout ).
Product surface: tabs.ts Ideasets tab.
- implementation
- reqlan.langium, types.ts, extract.rs, types.rs
- status
- done
- tests
- parsing.test.ts:parse ontology.rq ideas, linking.test.ts:resolve ideaset member forward reference, linking.test.ts:resolve forward reference to later ideaset in the same file
file
reqlan rq/ontology.rq
Files store ideas and form ideasets.
Documents use the `.rq` suffix ( file_suffix ) and file_layout.
Indexed as ideaset kind `file` in types.ts.
- implementation
- reqlan.langium, types.ts, extract.rs
- status
- done
- tests
- parsing.test.ts:parse syntax.rq, parser.rs:parse_syntax_rq
keyword
reqlan rq/ontology.rq
As a language, reqlan has keywords that are reserved in some contexts.
Import statement keywords: import_keywords ( `import`, `from`, `as` ).
Grammar: reqlan.langium — those tokens are keywords only at statement start.
Idea names should not use reserved keywords ( idea_name ).
- implementation
- reqlan.langium, reqlan-imports.ts
- status
- done
- tests
- parsing.test.ts:parse example sub idea.rq, parsing.test.ts:malformed from-as import keeps later ideas parseable
base
reqlan rq/ontology.rq
A base is a container for ideas, ideasets, and files — the boundary of one ideas graph.
Discovery: a directory is a base only when it owns a `.reqlan` application-memory folder.
There is no implicit base from a bare workspace folder; the product prompts the user to
create `.reqlan` at the workspace-folder root when none exist.
Bases may be nested: a child directory with its own `.reqlan` is a separate base;
the parent base's index stops at that child boundary.
Each base holds its own ideas index under its `.reqlan`. Details: base.
- implementation
- base-discovery.ts, base-registry.ts, application-memory.ts
- status
- done
- tests
- base-discovery.test.ts:returns empty when no .reqlan exists, base-discovery.test.ts:discovers base at workspace root, .reqlan
configuration
reqlan rq/ontology.rq
There are multiple scopes for configuration: at the base level and at the extension level.
Base config: configuration_location ( `<base>/.reqlan/config.json` ).
Base vs extension split: base_configuration.
- implementation
- reqlan-path-resolve.ts, config.schema.json
- status
- done
- tests
- config.test.ts:returns undefined when no config exists, config.test.ts:loads config from the owning base .reqlan, path-resolve.test.ts:loads importRoots list from nearest base config
import_statement
reqlan rq/ontology.rq
Imports describe references. Some keyword s are reserved for imports.
Forms: import_from, import_namespace,
import_qualified. Grammar: reqlan.langium `Import`; resolve: reqlan-imports.ts.
- implementation
- reqlan.langium, reqlan-imports.ts, reqlan-path-resolve.ts, ast.rs
- status
- done
- tests
- parsing.test.ts:parses from-import example line inside an attribute block value, linking.test.ts:resolve namespace import references to files, linking.test.ts:namespace import bracket reference links only the alias name
reference
reqlan rq/ontology.rq
References link ideas to other ideas, files, and symbols.
Syntax: reference_brackets, reference_wikilink,
reference_qualified, reference_file,
reference_url,
reference_embedding. Kinds: reference_types.
Grammar: reqlan.langium `ReferenceTarget`; index edges: extract.rs, rust_extract.
- implementation
- reqlan.langium, extract.rs, rust_extract, reqlan-file-link-resolver.ts, reqlan-definition-provider.ts
- status
- done
- tests
- linking.test.ts:resolve same-file bracket reference to local idea, linking.test.ts:resolve wikilink to idea declaration in main.rq, linking.test.ts:resolve namespace import references to files
referenced_files
reqlan rq/ontology.rq
Non- `.rq` files that ideas reference, or that reference ideas. These may be shared.
They should be captured in the index.
Outbound file refs: reference_file, file-reference-resolve.ts,
edge kind `file_reference` in types.ts.
Inbound comment refs: references_in_functional_code_comments
via reqlan-comment-resolver.ts / reqlan-comment.langium.
Full non- `.rq` file indexing of comment-bearing sources: index_code_files.
Click treats those files as centres: click_code_file.
- implementation
- file-reference-resolve.ts, reqlan-comment-resolver.ts, reqlan-comment.langium, extract.rs, comment.rs, register-comment-reference-links.ts
- status
- done
- tests
- file-reference-resolve.test.ts, references.test.ts:finds rq: bracket comment references in line comments, references.test.ts:finds rq: comment references in block comments, code_file_index.rs:indexes_comment_references_from_non_rq_files
cartographic_map
reqlan rq/ontology.rq
A cartographic map is a visual representation of a graph, optimised / curated by the user for context.
Product: graphical_graph ( graph_view ).
Distinct from a full-graph dump; atlas is a further curated overlay, not yet implemented.
- implementation
- graph_view, webview-graph-queries.ts, ideas-summary-panel.ts
- status
- done
extension
reqlan rq/ontology.rq
The extension contains the editor product features.
Host: main.ts; scope: vscode_extension, lsp_support.
Architecture: event_driven; packages: extension_package.
Domain hierarchy: extension_product, extension_domains.
- implementation
- main.ts, main.ts, package.json
- status
- done
grammar_rule
reqlan rq/ontology.rq
Grammar rules describe the syntax features.
Requirements: syntax.rq; lexer bridge: lexer_bridge_to_syntax.
Langium: reqlan.langium; comment grammar: reqlan-comment.langium; index-path AST: ast.rs.
- implementation
- reqlan.langium, reqlan-comment.langium, ast.rs, reqlan-token-builder.ts
- status
- done
- tests
- parsing.test.ts:parse syntax.rq, parser.rs:parse_syntax_rq, golden_corpus.rs:corpus_idea_names_match_langium_extract
attribute
reqlan rq/ontology.rq
Attributes are classification, functional, or nonfunctional metadata.
Syntax: attribute_marker, attribute_forms,
attribute_values, attribute_location.
Policy: attribute_configuration.
Indexed on types.ts `IdeaAttributeMap`; extract: extract.rs, rust_extract.
Product surface: tabs.ts Attributes tab.
- implementation
- reqlan.langium, types.ts, extract.rs, rust_extract
- status
- done
- tests
- parsing.test.ts:parses valued attributes without a colon, parsing.test.ts:treats mid-line @ as body text and line-start @ as attribute, extract_parity.rs:indexes_scalar_list_block_and_flag_attribute_values, extract_parity.rs:indexes_scalar_list_block_and_flag_attribute_values
attribute_body
reqlan rq/ontology.rq
The first attribute in an idea, if not marked otherwise, is the main body attribute. It is unstructured text.
Syntax: block_idea; extract summary from that body: extract.rs, rust_extract.
- implementation
- reqlan.langium, extract.rs, rust_extract
- status
- done
- tests
- extract_parity.rs:block_idea_body_populates_summary_from_rich_text_parts, extract_parity.rs:block_idea_body_populates_summary_from_rich_text_parts, extract_parity.rs:one_liner_idea_body_populates_summary
idea_name
reqlan rq/ontology.rq
The idea name is a string / handle / variable that uniquely identifies the idea ( within the ideaset / file ).
It should not be a reserved keyword.
Syntax: idea_name; grammar: reqlan.langium `IdeaName`.
- implementation
- reqlan.langium, ast.rs
- status
- done
- tests
- parsing.test.ts:parse dash and underscore delimited idea names, parser.rs:parse_dash_and_underscore_delimited_idea_names
atlas
reqlan rq/ontology.rq
A challenge with navigating complex graphs is that they can be overwhelming.
One extension to the product is to have atlases — named, reusable cartographic cuts beyond the live cartographic_map.
- idea
- true
- status
- draft
- todo
- specify atlas persistence and UI relative to graphical_graph
reference_types
reqlan rq/ontology.rq
reference
Kinds of reference_types. Details in reference_types.rq.
Index edge kinds live on types.ts / types.rs.
idea_reference
ideaset_reference
comment_reference
file_reference
link_reference
url_reference
wildcard_reference
click
reqlan rq/ontology.rq
A CLI / MCP function that returns compact local context for a given idea, file, or path.
No match uses search. More than one match is ranked by distance from the session.
One match returns idea content plus outbound, backlink, and sibling counts ( no edges ).
Indexed code files are click targets. Uses a SQLite click_session.
Count caps and session cache size are configurable.
see click
phonebook
reqlan rq/phonebook.rq
Canonical project links and publishable npm package URLs live in phonebook.json.
Modules that need contact, repo, marketplace, Discord, sponsorship, or npm package URLs should read from there instead of hardcoding values.
Typed access is shared via phonebook.ts for the site and extension README generator.
phonebook_icons
reqlan rq/phonebook.rq
Icon sets and lookup URLs live under the `icons` key in phonebook.json.
A link or package can omit `icon`. If `icon` is present, it references a set id ( `simple-icons`, `mdi`, … ) and slug `name` from that set's catalog.
Search a set at its `search` URL when renaming or replacing icons.
Surfaces render icons with Iconify via the packages listed in each set's `package` field per iconify_stack.
Site registry: phonebook-icons.ts per icon_registry.
npm_packages
reqlan rq/phonebook.rq
Publishable npm packages ( `@reqlan/language`, `@reqlan/analytical`, `@reqlan/cli`, `@reqlan/mcp` ) live under the `packages` key in phonebook.json.
Package ids are `language`, `analytical`, `cli`, and `mcp`.
The site Links section renders them under Packages per links / package_icons.
Typed helpers: `phonebookPackages`, `getPhonebookPackage` in phonebook.ts.
extension_readme_links
reqlan rq/phonebook.rq
The extension VSIX README uses phonebook link ids `site`, `github`, `vsc`, `openvsx`, `discord`, `github-sponsors`, and `email` for site, repository, marketplace, Open VSX, Discord, sponsorship, and contact URLs.
Generation is defined in extension_readme.
npm_package_readme_links
reqlan rq/phonebook.rq
Publishable npm package READMEs ( `@reqlan/language`, `@reqlan/analytical`, `@reqlan/cli`, `@reqlan/mcp` ) use the same phonebook link ids as extension_readme_links.
Generation is defined in npm_package_readme.
activity_bar_site_link
reqlan rq/phonebook.rq
The activity bar Context webview header info control opens phonebook link id `site` per info_site_link.
root_readme_links
reqlan rq/phonebook.rq
The repository README uses phonebook link ids `site`, `github`, `vsc`, `openvsx`, `discord`, `github-sponsors`, and `email` for site, repository, marketplace, Open VSX, Discord, sponsorship, and contact URLs.
Generation is defined in root_readme.
github_funding
reqlan rq/phonebook.rq
The GitHub sponsor button is configured in FUNDING.yml.
The GitHub Sponsors username is the account in phonebook link id `github-sponsors`.
Discord is community, not a funding platform: do not list it in FUNDING. yml.
- implementation
- FUNDING.yml
- status
- done
show_in_footer
reqlan rq/phonebook.rq
Each entry under `links` in phonebook.json may set `show-in-footer`.
The property is optional. Omitted means true.
Set `show-in-footer` to false to keep a link out of the site footer and the landing contact list.
Packages do not have this property.
Schema: phonebook.schema.json.
Typed helpers: `isShownInFooter`, `phonebookFooterLinks` in phonebook.ts and phonebook.ts.
per footer
per links
idea_reference
reqlan rq/reference_types.rq
Idea-to-idea reference: bracket `name` / `name` targets a local, imported, or same-file idea.
Syntax: reference_brackets, same_file_reference,
reference_qualified, reference_embedding,
references_to_subidea.
Index edge kind `references` on types.ts / types.rs. Extract: extract.rs, rust_extract.
A `member` form records the edge on the member leaf, not on the ideaset container.
An attribute uses the same brackets. See attribute_namespacing.
Wikilink surface for the same edge kind: link_reference. Fan-out across files: wildcard_reference.
- implementation
- reqlan.langium, types.ts, extract.rs, rust_extract
- status
- done
- tests
- linking.test.ts:resolve same-file bracket reference to local idea, linking.test.ts:resolve forward reference to later idea in the same file, linking.test.ts:same-file idea references produce document links, linking.test.ts:cross-file imported idea references produce document links, linking.test.ts:resolve ideaset-qualified bracket reference to member leaf not ideaset, extract_parity.rs:qualified_ideaset_member_reference_targets_leaf_idea_not_ideaset
ideaset_reference
reqlan rq/reference_types.rq
References to an ideaset or a namespace that behaves as one.
Syntax: ideaset; namespace import alias: import_namespace
( `alias` opens the imported file and links only the alias name ).
Membership edges are `ideaset_member`; a bare namespace-alias bracket is stored as `file_reference`
( extract.rs ), not `references`.
- implementation
- reqlan.langium, types.ts, extract.rs, types.rs
- status
- done
- tests
- linking.test.ts:resolve ideaset member forward reference, linking.test.ts:resolve forward reference to later ideaset in the same file, linking.test.ts:resolve namespace import references to files, linking.test.ts:namespace import bracket reference links only the alias name
comment_reference
reqlan rq/reference_types.rq
Inbound reference from comments in non- `.rq` source: `rq:idea` / `rq:idea`.
Qualified paths may use import-root aliases ( `rq:idea` ) per configuration_import_root_alias and comment_reference_import_root_alias.
Spec: references_in_functional_code_comments
Syntax note: comment_reference. Resolve: reqlan-comment-resolver.ts.
Unresolved: comment_reference_resolution_error.
Index edge kind `comment_link`. Related capture of those files: referenced_files.
Indexer: index_code_files.
- implementation
- reqlan-comment-resolver.ts, types.ts, register-comment-reference-links.ts, comment-reference-path-context.ts, reqlan-comment-diagnostics.ts, comment.rs
- status
- done
- tests
- references.test.ts:finds rq: bracket comment references in line comments, references.test.ts:finds rq: comment references in block comments, linking.test.ts:comment references in source files resolve to rq ideas, code_file_index.rs:indexes_comment_references_from_non_rq_files, comment-reference-resolution.test.ts:creates a document link for an import-root aliased comment reference, against the workspace folder for extension comment links
file_reference
reqlan rq/reference_types.rq
Outbound reference to a file, folder, or symbol — not only `.rq`.
Syntax: reference_file ( bracketed quoted path, optional `L#` / symbol path ).
Index edge kind `file_reference`. Resolve: file-reference-resolve.ts; extract: extract.rs.
Editor links: file_references.
Inbound file-reference CodeLens at the top of the target file:
file_inbound_code_lens.
Non- `.rq` targets and inbound comment traffic: referenced_files.
Markdown `label(target)` also stores this edge kind — see link_reference.
Quoted body text is not this kind: reference_edgecase.
- implementation
- file-reference-resolve.ts, extract.rs, types.ts, reqlan.langium, reqlan-file-link-resolver.ts
- status
- done
- tests
- file-reference-resolve.test.ts, linking.test.ts:empty file references produce document links and warning diagnostics, linking.test.ts:folder file references resolve without reading the directory as a file, references.test.ts:finds embedded file references in @tests lists
link_reference
reqlan rq/reference_types.rq
Link-shaped reference surfaces that are not a bare `idea` bracket.
Wikilink `target` ( optional alias pipe ): reference_wikilink —
indexes as idea-to-idea `references`, same as idea_reference.
Markdown `label(target)`: markdown_links — label is not an idea ref;
the target indexes as `file_reference` ( file_reference ).
- implementation
- reqlan.langium, extract.rs
- status
- done
- tests
- linking.test.ts:resolve wikilink to idea declaration in main.rq, parsing.test.ts:keeps pipe characters in body prose as text, references.test.ts:parses markdown link label and target from raw link text, references.test.ts:embedded file reference scan ignores markdown link labels
url_reference
reqlan rq/reference_types.rq
A bracket reference whose target is an absolute URL with a scheme and `://`.
Example: com/.
Syntax: reference_url.
Index edge kind `url_reference` on types.ts / types.rs. Extract: extract.rs, rust_extract.
check does not treat a URL reference as a missing idea or a missing file.
Unbracketed URLs in body prose stay text, not this kind.
Related: file_reference, link_reference.
- implementation
- reqlan.langium, types.ts, extract.rs, rust_extract, types.rs, reqlan-token-builder.ts, reqlan-file-link-resolver.ts, lexer.rs, parser.rs
- status
- done
- tests
- parsing.test.ts:parses bracketed url references, parsing.test.ts:does not parse unbracketed urls as url references, linking.test.ts:url references produce document links and no missing diagnostics, lexer.rs:bracketed_url_is_one_url_token, parser.rs:bracketed_url_is_a_url_reference, extract.rs:indexes_bracketed_url_as_url_reference, extract.rs:unbracketed_url_is_not_a_url_reference, broken_references.rs:check_accepts_url_references
wildcard_reference
reqlan rq/reference_types.rq
One reference that matches many ideas: quoted path glob + idea pattern ( `*` / `?` ).
Syntax and navigation: wildcard_references,
wildcard_references_webview.
Index: one `wildcard_reference` edge per catalog match
( wildcard_reference_edges ); never stored as plain `references`.
Native extract: extract.rs.
Sparse match handling: check_wildcard_sparse
( check_wildcard_zero, check_wildcard_one ).
- implementation
- extract.rs, types.rs, idea_extractor, types.ts, reqlan.langium, reqlan-wildcard-resolve.ts
- status
- done
- tests
- wildcard_reference_edges.rs:stores_wildcard_fan_out_as_wildcard_reference_kind, wildcard_reference_edges.rs:expands_wildcard_refs_to_one_edge_per_matching_idea, wildcard_reference_edges.rs:emits_unresolved_edge_when_catalog_has_no_matches, wildcard_reference_edges.rs:sync_persists_wildcard_reference_edges
reference_edgecase
reqlan rq/reference_types.rq
A quoted string is a file_reference only when it is inside brackets.
Example of a file reference: reference_types.rq
Example of body text: " this is not a reference. rq "
The file suffix does not change this rule.
The parser must not make a file reference from quoted body text.
The language server must not make a document link or a missing-file error from quoted body text.
Related: reference_edgecase, naked_strings_in_body, reference_file.
- implementation
- reqlan-embedded-file-references.ts, reqlan-file-link-resolver.ts, reqlan-token-builder.ts, extract.rs, reqlan.langium, lexer.rs
- status
- done
- tests
- references.test.ts:embedded file reference scan ignores unbracketed quoted paths, parsing.test.ts:does not parse unbracketed quoted paths as file references, naked-strings.test.ts:does not emit STRING tokens for unbracketed quoted paths in body, linking.test.ts:unbracketed quoted paths do not produce document links or missing-file diagnostics, file-path-rewrite.test.ts:does not treat unbracketed quoted paths as embedded path references, lexer.rs:unbracketed_quoted_path_in_body_is_not_string, parser.rs:unbracketed_quoted_path_is_not_a_file_reference, extract.rs:unbracketed_quoted_path_is_not_a_file_reference, extract.rs:import_quoted_path_is_not_an_embedded_file_reference
certs
reqlan rq/site/certs.rq
Certification lives under `/certs/`.
Pages:
- assessment_page at `/certs/assessment/` ( sole quiz when one assessment; catalog when more )
- one quiz per assessment at `/certs/assessment/id/`
- certificate_page at `/certs/certificate/`
The tutorials catalog and support_page advocacy link send the user to assessment_page.
Tokens are honor-system claims in certificate-token.ts.
Claim `a` is the assessment id ( not a section id ).
- implementation
- page.tsx, ["../../site/src/app/certs/assessment/id/page.tsx"], page.tsx, certs-paths.ts, certificate-token.ts, assessment.ts
- status
- done
assessment
reqlan rq/site/certs.rq
A named quiz with a stable id, a title, a blurb, and sections of questions.
Questions live in assessment.ts per copy.
Current sole quiz id `core`. Sections: ontology, installation, syntax, graph, cli.
Ontology covers idea, ideaset, file, base, attribute, attribute_body, reference.
Advanced syntax covers imports, file refs, wildcards, and comment refs.
CLI covers click and `reqlan check` for reference integrity in CI / CD.
Pass at 80 %. Then collect a display name and mint a certificate token.
The token claim `a` identifies this assessment.
After mint, go to certificate_page with the token and the just-completed query param.
- implementation
- assessment.ts, certificate-token.ts, AssessmentPage.tsx
- status
- done
assessment_page
reqlan rq/site/certs.rq
`/certs/assessment/` shows the sole assessment quiz when there is one.
When there is more than one assessment, it lists them.
`/certs/assessment/id/` is that assessment's quiz.
Unknown ids are not found.
Legacy `/assessment/` and `/tutorials/assessment/` redirect here and keep the query string.
The home quiz_sticker_tab links here. It does not run the quiz in the tab.
- implementation
- page.tsx, ["../../site/src/app/certs/assessment/id/page.tsx"], page.tsx, page.tsx, AssessmentPage.tsx, AssessmentListPage.tsx, assessment.ts, certs-paths.ts
- status
- done
certificate_page
reqlan rq/site/certs.rq
`/certs/certificate/` shows a minted certificate.
Token query param `c` holds the packed claims, including assessment id `a`.
Query param `just=1` marks the just-completed view:
- show the certificate
- show a shareable link that omits `just`
- embed the sticker form per sticker_form_embed
Without `just`, the page is the shareable certificate only. Do not embed the form.
Invalid or missing tokens send the user back to assessment_page.
The completion line on a valid certificate names the certificate_page and links to that quiz.
Legacy `/tutorials/certificate/` redirects here and keeps the query string.
- implementation
- page.tsx, page.tsx, CertificatePage.tsx, certs-paths.ts, certificate-token.ts, assessment.ts
- status
- done
sticker_form_embed
reqlan rq/site/certs.rq
The just-completed certificate_page embeds phonebook link id `sticker-form` as a Google Form iframe.
Href comes from phonebook, not a hardcoded URL in the view.
Convert the href to an embed `src` ( `viewform` plus `embedded=true` ).
Keep a direct link to the same phonebook href if the iframe does not load.
Hide the form when the user prints the certificate.
- implementation
- CertificatePage.tsx, google-form-embed.ts, phonebook.ts, phonebook.json
- status
- done
site
reqlan rq/site/site.rq
the / site folder contains a static Next. js App Router landing page for reqlan.
should align with brand
Copy modules: copy
Document head: meta_tags
simple_lightweight_and_static
reqlan rq/site/site.rq
must be fully statically exported for GitHub Pages.
All routes, including showcase detail pages, are generated at build time.
The deploy workflow must upload only static HTML, JS, and assets from site / out.
Build also embeds the workspace requirement graph under `/spec` per spec_html_export.
spec_html_export
reqlan rq/site/site.rq
The site static build exports the workspace requirement graph ( excluding `*.secret.rq` ) under `out/spec/` via `reqlan export`.
It must pass html_export_url_base for `/spec` ( honouring `SITE_BASE_PATH`, e. g. `/reqlan/spec` in production ) so `/spec` loads with or without a trailing slash.
It must pass html_export_header_link pointing at the marketing site home so readers can leave the embedded spec and return to the parent site.
Embedded `/spec` graph pages inherit html_export_graph_background_load so large workspace graphs do not freeze the page while settling.
Pipeline: build-static.mts → export-spec.mts → verify-static-export.mts.
Host options come from html_export / CLI commands, including native CLI export via native_bridge.
CI must build / stage host `reqlan-napi` before this pipeline ( site_distribution ); the loader probes repo-root `crates/target`, not `packages/crates`.
- implementation
- export-spec.mts, verify-static-export.mts, build-static.mts, deploy-site.yml, load-native.ts, native-analysis-api.ts, types.rs, api.rs
- status
- done
- tests
- verify-static-export.mts, native-export-request.test.ts, load-native.test.ts, native-packaging.test.ts, export.rs:html_export_honours_graph_page_url_base_and_header_link
workflow
reqlan rq/site/site.rq
Site deployment runs when an `site/v*` tag is pushed.
Tags are created automatically on main by the release workflow per deployment_flow.
The site workflow does not deploy on ordinary commits.
per site_distribution
routes
reqlan rq/site/site.rq
Marketing routes are statically generated App Router pages under app.
Home `/` hosts landing sections; other top-level pages include quickstart per quickstart_page, tutorials, showcase, FAQ per faq_page, support per support_page, certification per certs, and the embedded `/spec` export.
per sidebar_nav
per faq_page
per quickstart_page
per support_page
per certs
components
reqlan rq/site/site.rq
- sidebar per sidebar_nav
- footer per footer
- hero per hero_section
- sticky page nav graph per nav_graph
- links / contact per links
- showcases
- tutorials per tutorials_section
- certification per certs
- FAQ per faq_page
- support per support_page
- content per copy
- elevator pitch per elevator_pitch_section
- featured-in social proof per featured_in_section
- motivation per motivation_section
- syntax per syntax_section
- example per example_section
- roadmap per roadmap_section
- CTA:
- install the extension and the CLI
per cta_icon
per install_cli_menu
- GitHub star on the hero action row per hero_github_star
- sticky draggable action buttons per sticky_cta_node
- home-only quiz sticker edge tab per quiz_sticker_tab
- 404 page ( just something silly / a redirect )
hero_section
reqlan rq/site/site.rq
Landing `#hero`: mascot plus a short `.rq` snippet.
Copy lives in hero.ts per copy.
The snippet must parse as accurate reqlan per accurate_rq_snippets_must_parse.
Install controls are cta_icon and install_cli_menu; get-started CTA href is `/quickstart` per quickstart_page.
Get-started motion follows get_started_cta_motion.
A GitHub star control sits in the action row per hero_github_star.
- implementation
- hero.ts, Hero.tsx, HeroActions.tsx
- status
- done
get_started_cta_motion
reqlan rq/site/site.rq
The get-started control on hero_section shows a moving colour wash on the border and on the button fill.
The wash uses the aqua and rust brand colours.
The border wash and the fill wash share one spin period and one spin direction.
When the visitor prefers reduced motion, show a static fill and a static border.
per styling_architecture
- implementation
- hover-border-gradient.tsx, hover-border-gradient.module.css, HeroActions.tsx
- status
- done
hero_github_star
reqlan rq/site/site.rq
The hero_section action row shows a Star on GitHub control next to get-started and the install controls.
The control opens the GitHub repository from phonebook in a new tab.
The icon comes from phonebook_icon_component.
Copy lives in hero.ts per copy.
The hero control is in addition to sticky_cta_node and support_page.
- implementation
- hero.ts, HeroActions.tsx, HeroActions.module.css
- status
- done
elevator_pitch_section
reqlan rq/site/site.rq
Landing `#elevator-pitch` after hero_section and before featured_in_section.
This is the home " Why reqlan " destination: sidebar_nav child and nav_graph Why node use this id.
One-line thesis plus rotating claims.
Copy lives in meta.ts per copy.
Thesis follows elevator_pitch.
Behaviours: claim_cycle, claim_progress, claim_reduced_motion, claim_expand.
Styling per styling_architecture. Must stay compatible with simple_lightweight_and_static.
- implementation
- meta.ts, nav.ts, ElevatorPitch.tsx, ElevatorPitch.module.css, NavGraph.tsx, HomePage.tsx
- status
- done
- tests
- nav.test.ts
featured_in_section
reqlan rq/site/site.rq
Landing `#featured-in` after elevator_pitch_section and before motivation_section.
Rolling social-proof banner: label " As featured in: " plus catalogue cards that scroll slowly in a continuous loop.
Each card shows an icon and an outbound link label.
Required listings ( labels match the catalogue names ):
- agentlanguages. dev → https://agentlanguages.dev/languages/reqlan/
- awesome-spec-driven-development → https://github.com/Engineering4AI/awesome-spec-driven-development
- awesome-docs → https://github.com/testthedocs/awesome-docs
Copy and icons live in featured.ts per copy.
Icons resolve through phonebook_icon_component / icon_registry.
Links open in a new tab with `rel="noopener noreferrer"`.
Pause the scroll on hover or focus. When the visitor prefers reduced motion, show a static row of the same cards with no scroll.
Do not put these URLs in the phonebook footer / contact list.
Styling per styling_architecture. Must stay compatible with simple_lightweight_and_static.
- implementation
- featured.ts, FeaturedIn.tsx, FeaturedIn.module.css, HomePage.tsx, site.ts
- status
- done
- tests
- featured.test.ts
claim_cycle
reqlan rq/site/site.rq
Show one claim at a time and cycle in order.
Pause on hover or focus. Tracks jump to a claim.
The active claim sits in the vertical centre of a slot sized for the longest claim, so shorter lines do not jump to the top.
- implementation
- ElevatorPitch.tsx, ElevatorPitch.module.css
- status
- done
claim_progress
reqlan rq/site/site.rq
A track per claim shows hold-time state: past tracks are full, the current track fills left to right, later tracks stay empty.
Pause holds the fill. The fill and the cycle share one clock so they do not drift.
- implementation
- ElevatorPitch.tsx, ElevatorPitch.module.css
- status
- done
claim_reduced_motion
reqlan rq/site/site.rq
When the visitor prefers reduced motion, show the full claim list with no cycle and no progress animation.
- implementation
- ElevatorPitch.tsx, ElevatorPitch.module.css
- status
- done
claim_expand
reqlan rq/site/site.rq
A toggle expands every elevator_pitch_section claim into one list.
The rotating cycle stays the default.
Expanding pauses the cycle. Collapsing returns to the cycle.
Reduced motion still starts on the list per claim_reduced_motion.
- implementation
- ElevatorPitch.tsx, ElevatorPitch.module.css
- status
- done
motivation_section
reqlan rq/site/site.rq
Landing `#motivation` after featured_in_section: what / why slides for language, extension, CLI, and MCP.
Copy lives in motivation.ts per copy.
- implementation
- motivation.ts, Motivation.tsx, MotivationClient.tsx
- status
- done
syntax_section
reqlan rq/site/site.rq
Landing `#syntax`: self-explanatory rule + practical snippet pairs ( show, don't tell ).
Copy lives in syntax.ts per copy.
Highlighting languages follow code_block_styling.
language- " rq " pairs must parse per accurate_rq_snippets_must_parse.
- implementation
- syntax.ts, Syntax.tsx, SyntaxClient.tsx, generate-highlights.mts
- status
- done
example_section
reqlan rq/site/site.rq
Landing `#example`: one worked graph slice ( imports, file anchors, wildcards, status, tags, tests ).
Copy lives in example.ts per copy.
The slice must parse as accurate reqlan per accurate_rq_snippets_must_parse.
- implementation
- example.ts, Example.tsx
- status
- done
- tests
- example.test.ts:parses as valid reqlan
accurate_rq_snippets_must_parse
reqlan rq/site/site.rq
Every site snippet that demonstrates accurate reqlan must parse against the Langium grammar.
In scope: language- " rq " blocks ( landing syntax pairs, the example slice, the hero snippet, showcase `.rq` blocks ).
Out of scope: ts / md / py snippets that only show `rq:` comment links.
Invalid-on-purpose samples must not be labelled language- " rq ".
Enforced by tests plus the content parse gate in validate-showcase-rq.mts.
Showcases are a subset per every_rq_block_must_parse / phase_1_parse_gate.
- implementation
- parse-rq-snippet.ts, accurate-rq-snippets.ts, example.ts, syntax.ts, hero.ts, showcases, validate-showcase-rq.mts
- status
- done
nav_graph
reqlan rq/site/site.rq
Sticky landing page graph. Node / edge model and labels live in nav.ts per copy / sidebar_nav.
Section nodes match home anchors; page nodes match top-level routes in routes.
sidebar_nav
reqlan rq/site/site.rq
The site sidebar is a hierarchical page nav, not a flat list of mixed anchors and routes.
Top-level entries are pages ( or the home hub ). Same-page section anchors nest as children under their parent page.
Children render only while the visitor is on that parent page — off-page section lists stay collapsed so the sidebar reflects the current route.
Until pathname is known after mount, children stay closed ( do not default to Home ) so static HTML / hydration does not flash a mismatched hierarchy.
The active page uses `aria-current="page"`; the in-view same-page section uses `aria-current="location"` when known.
Nav model and labels live in nav.ts per copy; the Sidebar client reads pathname ( and hash / section when on home ) to decide expansion and current markers.
FAQ is a top-level page entry per faq_page.
Support is a top-level page entry per support_page.
Sidebar nests Support section anchors as same-page children.
faq_page
reqlan rq/site/site.rq
The site exposes `/faq/` as a statically generated page answering a short set of common questions.
Copy lives in faq.ts and stays minimal per copy. Support answers point at support_page and at phonebook surfaces ( GitHub stars, marketplace stars, issues / contribution, GitHub Sponsors, Discord ) rather than inventing URLs.
Required topics:
- how reqlan supports token efficiency
- whether reqlan is the de facto standard for efficient developer-centric context management and semantic mapping
- when to use reqlan
- how `.rq` files stay in sync with code per faq_drift
- how to support reqlan ( GitHub stars, GitHub Sponsors, VS Marketplace stars, Discord, contribution, bug reporting )
Sidebar nests FAQ question anchors as same-page children per sidebar_nav.
Landing nav graph includes FAQ as a page node.
- implementation
- page.tsx, FaqPage.tsx, faq.module.css, faq.ts, nav.ts, Sidebar.tsx, NavGraph.tsx
- status
- done
- tests
- faq.test.ts
faq_drift
reqlan rq/site/site.rq
The FAQ includes this question: How do you keep `.rq` files from drifting once the code moves on?
`.rq` files are code. They are the source of truth. They are not a document.
Specify material work as an idea first.
Implementation and tests point back with rq-comments per code_comment_references and testing.
A check requires each test to serve a requirement.
Agents see only the ideas that attach to the files they touch.
Mark a replaced idea deprecated and point to the new idea.
The indexer flags missing references like a compile check.
Copy lives in faq.ts ( item id `drift` ) per copy and faq_page.
The sidebar nests this question as a same-page child per sidebar_nav.
- status
- done
- tests
- faq.test.ts
quickstart_page
reqlan rq/site/site.rq
The site exposes `/quickstart/` as the install / get-started page.
Primary path: editor install chooser.
Also explains headless cli_package ( `@reqlan/cli` ) and mcp_package ( `@reqlan/mcp` ) on the same `.reqlan` index.
Package npm hrefs come from npm_packages, not hardcoded URLs.
CLI and MCP install commands offer npm, pnpm, yarn, and bun per install_cli_menu.
They share one stored preference per package_manager_preference.
After install steps, it links onward to Tutorials, Showcases, and FAQ so visitors can continue without returning to the home nav.
Related link copy lives in quickstart.ts per copy.
Sidebar nests Extension / CLI / MCP as same-page children per sidebar_nav.
- implementation
- page.tsx, QuickstartPage.tsx, QuickstartClient.tsx, QuickstartClient.module.css, quickstart.ts, nav.ts
- status
- done
roadmap_section
reqlan rq/site/site.rq
Landing page section `#roadmap` after example and before links.
Compact vertical scaled-center carousel ( snap + distance-based scale / opacity peeks ).
Flat Now / Next / Later items — one focused at a time; neighbours peek smaller.
Copy lives in roadmap.ts ( per copy ); nav and sticky page graph include the section.
Keep the list honest and thin — no fake dates, no wall of tickets.
- implementation
- Roadmap.tsx, roadmap.ts, HomePage.tsx, NavGraph.tsx
- status
- done
- todo
- refresh items when product priorities shift
tutorials_section
reqlan rq/site/site.rq
The site exposes `/tutorials` and `/tutorials/slug/` as statically generated pages.
Catalog and deck ids come from authored manifest.jsonc.
Each detail page embeds the Reveal player iframe at `/presentations/player/?deck=<id>` using assets / SITE_BASE_PATH-aware `sitePath`.
Each detail page hosts a unified transport chrome ( `<<` `<` steps `>` `>>` ) that drives slide nav in the embedded player via postMessage, plus lesson jumps ( tutorial_player_transport ).
Location hierarchy chrome: tutorial_location_crumb.
Blurb and try-this live on the catalog and inside the slides, not as page chrome.
The player is an App Router page ( presentation_player_route ) so it static-exports under `trailingSlash` without colliding with `public/` HTML.
Sync ( sync_presentations ) converts authored deck / catalog JSONC under presentations into runtime JSON under `public/presentations/`, and copies assets plus vendored Reveal. js ( player shell excluded ).
The catalog links to assessment_page for certification.
- implementation
- page.tsx, ["../../site/src/app/tutorials/slug/page.tsx"], page.tsx, tutorials.ts, TutorialPlayerShell.tsx, PresentationPlayer.tsx, sync-presentations.mts, parse-jsonc.ts
- status
- done
tutorial_location_crumb
reqlan rq/site/site.rq
Tutorial detail chrome shows a compact location trail: catalog → course → lesson → slide.
Hierarchy must be obvious without a wide single-line title dump.
Layout: each tier is a stacked chip — role ( and optional completion control ) on the top row;
title / index value muted underneath. Titles colour up on hover, focus-within, or when the peer menu is open.
**Folder navigation: ** each tier acts like a path segment / folder. Hover or focus reveals a peer menu
for that level of the tree so the user can jump without using the transport row:
- catalog → courses ( enter first lesson of the chosen course, or the catalog index )
- course → peer courses
- lesson → peer lessons in the active course
- slide → peer slides in the active lesson ( updates the embedded player / `?slide=` )
Current peer is marked; menus stay keyboard-reachable via focus-within.
**Sizing: ** the crumb container grows to fit text; wrap before truncating. Ellipsis only as a last resort
on very narrow viewports — do not cap chip width so aggressively that titles ellipsize while space remains.
Course deep-links also exist at `/tutorials/#course-<series>`; catalog at `/tutorials/`.
Slide shows `n/total` and updates live with the embedded player.
Completion toggles stay on the role row.
The crumb lesson tier always shows the **current** lesson only — it must not share hover / preview
state with the transport lesson step dots. Step-dot hover may preview a title near the dots, never in the crumb.
- implementation
- TutorialPlayerShell.tsx, TutorialPlayerShell.module.css
- status
- done
tutorial_player_transport
reqlan rq/site/site.rq
The `<` control must show the previous slide when the player can go back.
When the player cannot go back, `<` must open the previous lesson if that lesson exists.
Open that lesson on the last slide.
The `>` control must show the next slide when the player can go forward.
When the player cannot go forward, `>` must open the next lesson if that lesson exists.
Open that lesson on the first slide.
The Left Arrow key and the Right Arrow key must do the same as `<` and `>`.
Shift + Left Arrow and Shift + Right Arrow must open the adjacent lesson from any slide.
The `<<` and `>>` controls must continue to open the adjacent lesson.
After the current lesson player is ready, the shell must start to load the next lesson player in the background.
The shell must prefetch the next lesson page.
The shell must ignore state messages from the background player.
- status
- done
sync_presentations
reqlan rq/site/site.rq
`scripts/sync-presentations.mts` reads authored `*.jsonc` decks and `manifest.jsonc`, emits comment-free `*.json` for the static player, and syncs assets / vendor into `public/presentations/`.
- implementation
- sync-presentations.mts, parse-jsonc.ts
- status
- done
sync_config_schema
reqlan rq/site/site.rq
`scripts/sync-config-schema.mts` copies the canonical base config JSON Schema from config.schema.json into `public/schemas/v1/config.schema.json`.
Public URL: `https://reqlan.com/schemas/v1/config.schema.json` ( path `v1` is schema compatibility; not site package semver ).
Canonical authoring and `$id`: configuration_schema_file.
Init seed `$schema`: base_config_seed.
Wired into site `predev` and `build-static` ( same pattern as sync_presentations ). Deployed with existing `site/v*` pipeline.
Synced artifact is not a second authoring source; do not edit under `public/schemas/`.
- implementation
- sync-config-schema.mts, build-static.mts, config.schema.json
- status
- done
- tests
- config.test.ts:schema $id matches public v1 host path, config.test.ts:schema file documents importRoots mappings
presentation_player_route
reqlan rq/site/site.rq
`/presentations/player/` is a statically exported Next page that loads runtime deck JSON from `/presentations/decks/` and Reveal from `/presentations/vendor/reveal.js/`.
Runtime JSON is generated from authored JSONC by sync_presentations.
It must not use SiteShell; it is iframe-hosted by tutorial detail pages.
Do not place `public/presentations/player/index.html` — that path is owned by the App Router export.
- status
- done
code_block_styling
reqlan rq/site/site.rq
Code blocks should be styled per language as a function of a classname; or by using an appropriate lightweight external dependency.
Language ids live in types.ts. CodeLanguage —. rq,. ts,. md,. py, plus st / c / json / yaml for showcases.
If using a dependency, it should parse at build, not in the browser.
- implementation
- types.ts, highlight.ts, CodeBlock.tsx, generate-highlights.mts
logo
reqlan rq/site/site.rq
- there is a logo in the sidebar.
assets
reqlan rq/site/site.rq
this site is published in in gh pages at the `/reqlan` path. Any assets in the / public folder should be referenced as `/reqlan/assets/...`.
Embedded spec export hrefs follow the same base via spec_html_export / html_export_url_base.
brand
reqlan rq/site/site.rq
must be aligned with brand.rq
images
reqlan rq/site/site.rq
The source logo is in the / public folder. A sharp dev script is used to generate pngs and favicons etc which should be executed if the svg source logo changes.
The script also writes the Open Graph image `/og.png` ( 1200 × 630 ) per meta_tags.
- implementation
- generate-images.mjs, logo.svg, og.png
meta_tags
reqlan rq/site/site.rq
The site HTML head must include a document title, a description, a canonical URL, Open Graph tags, and Twitter card tags.
Canonical origin is the phonebook `site` href per phonebook.
Default title and description live in meta.ts per copy.
Root layout layout.tsx sets the shared metadata: title template `%s · reqlan`, description, icons, manifest, theme colour, Open Graph image, and Twitter `summary_large_image`.
Each marketing page must set a title and a description. Showcase and tutorial detail pages use the item title and summary.
Open Graph image is 1200 × 630 PNG at `/og.png`, generated with favicons per images.
Compatible with simple_lightweight_and_static.
Do not index the presentation player route per presentation_player_route.
copy
reqlan rq/site/site.rq
Marketing copy lives in typed TS modules under content, composed by site.ts.
Shared types: types.ts.
Copy stays decoupled from layout / styling.
Copy should be really super minimal and concise if at all. ( show don't tell )
Copy should be user facing; not simply a description of the feature requirements. Production code doesn't have latent dev notes in visible components.
Landing modules: hero_section, elevator_pitch_section, featured_in_section, motivation_section, syntax_section, example_section, roadmap_section, nav_graph, faq_page, sidebar_nav, links, footer, sticky_cta_node, quiz_sticker_tab.
- implementation
- types.ts, site.ts, meta.ts, nav.ts, hero.ts, featured.ts, motivation.ts, syntax.ts, example.ts, roadmap.ts, contact.ts, faq.ts, support.ts, sticky-cta.ts, quiz-sticker.ts, assessment.ts
- status
- done
footer
reqlan rq/site/site.rq
The site footer is on every page via SiteShell.tsx.
Copyright copy lives in meta.ts per copy.
The footer shows phonebook `links` where `show-in-footer` is not false per show_in_footer.
Icons render through phonebook_icon_component.
links
reqlan rq/site/site.rq
per phonebook
per npm_packages
per show_in_footer
Contact copy lives in contact.ts per copy.
Contact shows phonebook `links` that are not opted out of the footer, then a Packages subsection for phonebook `packages`.
per link_icons
per package_icons
- implementation
- contact.ts, Contact.tsx
- tests
- contact.test.ts
icon_registry
reqlan rq/site/site.rq
phonebook-icons.ts maps phonebook icon keys to bundled Iconify data for the site.
A link or package can omit `icon`. If `icon` is present, it must have a matching registry entry.
The module throws at startup if a present icon does not resolve.
When you add or change an icon in phonebook.json, update the registry import for that slug.
per iconify_stack
per phonebook_icon_keys
- status
- done
phonebook_icon_component
reqlan rq/site/site.rq
PhonebookIcon.tsx is the site's single render entry point for phonebook icons ( `@iconify/react` ).
It accepts an optional phonebook `icon` ref. If the ref is absent, it renders nothing. If the ref is present, it renders an inline SVG with `aria-hidden`.
Default sizing uses the `.phonebook-icon` class in globals.css.
Must remain compatible with static export per simple_lightweight_and_static.
per iconify_stack
link_icons
reqlan rq/site/site.rq
The contact link row in Contact.tsx renders an icon beside each phonebook link label that has an icon.
Footer links that have an icon render through phonebook_icon_component per footer.
per links
per current_link_icons
package_icons
reqlan rq/site/site.rq
The contact Packages row in Contact.tsx renders an icon beside each phonebook package label that has an icon.
Package entries come from phonebook.json. packages per npm_packages.
per links
per current_link_icons
cta_icon
reqlan rq/site/site.rq
The hero has a separate " Install extension " menu button.
The menu lists Cursor, VS Code, and Download VSIX.
It must not include Open VSX. Open VSX stays on quickstart_page.
It must not assume the user's editor or pre-select one silently.
The CLI control is a separate button per install_cli_menu.
Get-started CTA copy lives in hero.ts per hero_section.
Each menu row shows the target's icon beside its full label; icons resolve through phonebook-icons.ts via the quickstart icon set / name refs in install-actions.ts.
per components
per iconify_stack
- implementation
- hero.ts, install-actions.ts, HeroActions.tsx, InstallSplitButton.tsx, quickstart-icons.ts
- status
- done
install_cli_menu
reqlan rq/site/site.rq
The hero has a separate " Install CLI " control. It must not nest inside cta_icon.
The primary action copies the selected package manager command for cli_package per package_manager_preference.
A chevron menu lists npm, pnpm, yarn, and bun.
Each command uses the CLI package name from npm_packages.
A click copies the selected command to the clipboard and stores the preference.
The quickstart_page CLI and MCP install rows use the same package manager options and the same preference.
A copy must not change the last-used editor.
package_manager_preference
reqlan rq/site/site.rq
The site keeps one global JavaScript package manager value: npm, pnpm, yarn, or bun.
The default is npm.
All CLI and MCP install commands read and write this one value. Do not keep a separate choice on each control.
The value persists in the browser across pages and reloads.
Surfaces: install_cli_menu, quickstart_page.
Compatible with simple_lightweight_and_static.
- implementation
- package-manager.ts, use-package-manager.ts, InstallSplitButton.tsx, QuickstartClient.tsx
- status
- done
sticky_cta_node
reqlan rq/site/site.rq
Root layout layout.tsx hosts a sticky, draggable button tray on marketing pages.
The tray stays in the viewport. Drag starts from a dedicated handle only — action links must not capture pointer or begin a drag.
The drag / hit box is the button tray only ( `width` / `height`: fit-content ). Labels and tooltips overlay outside that box; they must not enlarge it.
Compact state is icon-only. Hover / focus expands the matching label as a tooltip beside ( web ) or above ( mobile ) the icon, flipped if the tray is near that viewport edge.
Narrow ( mobile ) viewports show one action: star the GitHub repository.
Wider ( web ) viewports also show " Try the extension ", which opens quickstart_page.
GitHub href and icons come from phonebook / phonebook_icon_component, not hardcoded URLs or ad-hoc glyphs.
Copy lives in sticky-cta.ts per copy.
Do not show the tray on the presentation player route per presentation_player_route.
- implementation
- layout.tsx, sticky-cta.ts, StickyCtaNode.tsx
- status
- done
quiz_sticker_tab
reqlan rq/site/site.rq
Home only: a right-edge tab on the home page. It does not mount in root layout or on other routes.
Collapsed: a vertical label and the phonebook `sticker-form` icon.
Open: a short panel. The CTA is a link to assessment_page through certs-paths.ts. It is not an in-place quiz.
Copy lives in quiz-sticker.ts per copy.
Style with CSS modules per styling_architecture and brand. Use theme colour tokens. Hide on narrow viewports so it does not cover content.
Keep it compatible with simple_lightweight_and_static and sticky_cta_node.
No looping decorative motion. Open and close may change width once. When the visitor prefers reduced motion, do not animate.
- implementation
- quiz-sticker.ts, QuizStickerTab.tsx, QuizStickerTab.module.css, HomePage.tsx
- status
- done
styling_architecture
reqlan rq/site/site.rq
styling should be handled primarily at the compoenent level with co-located css module files that are imported in the react components.
showcase
reqlan rq/site/site.rq
Every showcase demonstrates a mechanism, not a metaphor.
Domain problem, the. rq that binds it, the real artifact in another language
it binds to, and the thing the tooling hands back.
Content is authored in TS objects per showcase_module, not generated from this file at runtime.
This file is the source of truth for intent, ordering, and editorial rules.
- implementation
- showcases, showcase, ShowcaseListPage.tsx, ShowcaseDetailPage.tsx
- status
- done
showcase_thesis
reqlan rq/site/site.rq
Current showcases demonstrate the syntax, not the toolset.
A reader who finishes them thinks: you can write sentences in curly brackets.
Nothing shows what you get back — no query and answer, no diagnostic, no graph, no round trip.
The upgrade thesis:
every showcase demonstrates one mechanism against a real domain problem.
Code in, artifact out. No showcase ships without a payoff block.
showcase_problems
reqlan rq/site/site.rq
Three concrete failures of the current set:
Invalid reqlan.
Samples use illegal attribute forms ( colon-list tags, pipe-scalar plans,
nested reference objects ) that do not parse against the langium grammar.
For a language project, shipping invalid samples on the marketing site is an own-goal.
Prose dressed as semantics.
A file ref followed by the word " implements " and an idea ref reads like a typed
relation, but " implements " is body text. Reqlan has five edge kinds
( references, wildcard_reference, file_reference, ideaset_member, import, comment_link )
and none are user-declared. We imply a feature that does not exist while
hiding the ones that do.
Vapor features.
Graph showcase tells people to run Reqlan: Export JSON, which is not registered.
The docs-attribute page is built around an attribute with no special tooling.
every_rq_block_must_parse
reqlan rq/site/site.rq
Every language- " rq " block in showcase content files must parse against the langium grammar.
Prefer enforcement via a build step that runs the real parser over content.
Site-wide ( landing + showcases ): accurate_rq_snippets_must_parse.
aligns with phase_1_parse_gate
every_showcase_ends_in_a_payoff
reqlan rq/site/site.rq
A diagnostic, a query response, a coverage report, or a graph.
If there is no tooling output, it is not a showcase.
one_worked_example_per_page
reqlan rq/site/site.rq
Consistent identifiers across every block on a page.
The reader should trace one name from requirement to source to test to
search result without re-orienting.
diagrams_are_never_dressed_as_code
reqlan rq/site/site.rq
ASCII arrow diagrams must not sit inside language- " rq " blocks.
They get their own visually distinct block kind.
aligns with showcase_module
showcase_rules
reqlan rq/site/site.rq
Four editorial rules. Enforced in content and, where possible, at build time.
See every_rq_block_must_parse, every_showcase_ends_in_a_payoff,
one_worked_example_per_page, diagrams_are_never_dressed_as_code.
showcase_rules_set
reqlan rq/site/site.rq
Ideaset (showcase_rules_set)
sub_file_binding
reqlan rq/site/site.rq
Symbol refs `auth.ts".login`, line ranges adc.cL#41-58,
and test-name anchors x.test.ts:rejects expired token.
Requirements attach to code at symbol granularity, in any language.
bidirectional_comment_links
reqlan rq/site/site.rq
rq-comment refs in TS, Python, C, ST, etc.
Code points back, with working document links.
A product story bound this way is story_codebase_showcase.
features_tier_1
reqlan rq/site/site.rq
The reasons to adopt. All verified as shipping today.
- subreqs
- sub_file_binding, bidirectional_comment_links, refs_break_loudly { Unresolved references are error diagnostics with quick-fix code actions. File moves prompt to rewrite every inbound ref. The same check is check (`reqlan check`, exit 1), so CI can reject rot. Demonstrated by broken_links_showcase. }, mcp_as_shaped_context { MCP `click` is the search and retrieval tool (mcp_click_retrieval). Hand an agent compact unique context, ranked matches, or search hits — not forty files. }
features_tier_2
reqlan rq/site/site.rq
The depth. Also shipping.
- subreqs
- imports_aliases_and_root_config { Imports, aliases, and root-alias config. Ideasets as a module's published surface. }, attribute_grammar_breadth { Flags, negated flags, block values, nested and named lists. Arbitrary at-keys as a domain dialect. }, completion_and_deprecation_analysers { Reqlan: Completion Status and Reqlan: Deprecation Impact — real shipped analysers nobody is showing. }, cytoscape_graph_view { Status/tag filters, indirect-reference depth toggle, and Wildcard refs edge toggle (wildcard_refs_toggle). }, wildcard_path_idea_refs { Qualified path + idea-pattern references — `*.rq".*_pane` — fan out across files as `wildcard_reference` edges (wildcard_reference_edges); navigation opens a matches panel. See wildcard_references, wildcard_refs_toggle. }, html_multipage_export { HTML multi-page export as an actual deliverable. }
features_not_demonstrated
reqlan rq/site/site.rq
Deliberately not demonstrated — they do not exist yet.
Typed relation kinds, hover cards, autoformatting,
JSON / CSV export palette commands, PDF binary, vector-embedding search.
Keyword-scored search must not be marketed as semantic search / embeddings.
agent_context_showcase
reqlan rq/site/site.rq
Flagship. Context for the agent, not the repo.
An agent answers a question about session expiry.
Show the repo-dump cost, then MCP click returning compact file context,
then the plan the agent writes.
Absorbs former agentic-planning and feature-tracking pages.
- domain
- ai-tooling
- implementation
- agent-context.ts
- mechanism
- mcp_tools, token_discipline
- status
- done
- tier
- flagship
interlock_showcase
reqlan rq/site/site.rq
Flagship. The interlock that must not fail.
`interlock.stL#41-58`
A safety requirement bound to that PLC symbol and line range,
line range, to a vitest case by test name, with an rq-comment in the ST
source pointing back.
Domain: industrial control / IEC 61131.
- domain
- industrial-control
- implementation
- interlock.ts
- mechanism
- symbol_refs, line_ranges, test_anchors, comment_links
- status
- done
- tier
- flagship
broken_links_showcase
reqlan rq/site/site.rq
Flagship. Links that break loudly.
Someone renames a file. Show the diagnostic, the quick-fix menu, and the
rewritten refs. Then the same issue from check
( `reqlan check`, exit 1 ) and that command as a CI step so a merge cannot land rot.
This is the argument against a wiki.
Domain: refactor safety, any stack.
- domain
- refactor-safety
- implementation
- broken-links.ts
- mechanism
- unresolved_ref_diagnostics, code_actions, file_mutation_hooks, check, ci
- status
- done
- tests
- showcases.test.ts:broken-links shows reqlan check as a CI gate
- tier
- flagship
firmware_cloud_contract_showcase
reqlan rq/site/site.rq
Flagship. The contract between firmware and cloud.
A 10 Hz sample rate and a 50 ms ingest deadline: one invariant, two
codebases, neither of which can express it alone.
Absorbs half of former glue-semantics and static-connection.
- domain
- embedded-backend
- implementation
- firmware-cloud.ts
- mechanism
- cross_stack_file_refs, idea_as_connective_tissue, inbound_reference_inlay_hints
- status
- done
- tier
- flagship
story_codebase_showcase
reqlan rq/site/site.rq
Flagship. A story that ships with the code.
Write the feature as one idea. Bind source with @ implementation.
Bind proof with @ tests. Point back with rq: comments.
Click on that name returns the bound files — not a ticket outside the repo.
Domain: product delivery.
One worked name across every block per one_worked_example_per_page.
Payoff is click output per every_showcase_ends_in_a_payoff
and click.
Uses code_comment_references and testing.
Demonstrates sub_file_binding and bidirectional_comment_links.
- domain
- product-delivery
- implementation
- story-codebase.ts, index.ts
- mechanism
- implementation_attribute, tests_attribute, comment_links, click
- status
- done
- tests
- showcases.test.ts:story-codebase binds a story to source and tests, showcases.test.ts:gives each showcase its own file with rq comment references, validate-showcase-rq.mts
- tier
- flagship
audit_trail_showcase
reqlan rq/site/site.rq
Depth. An audit trail you can export.
Custom clause / evidence / verified_by attributes, then Completion Status
showing the coverage gap, then HTML export as the auditor's deliverable.
Domain: regulated software — IEC 62304 or SOC 2.
Absorbs former compliance page.
- domain
- regulated-software
- implementation
- audit-trail.ts
- mechanism
- custom_attributes, completion_status, html_export
- status
- done
- tier
- depth
module_surface_showcase
reqlan rq/site/site.rq
Depth. A module's published surface.
billing / interface. rq exports an ideaset; checkout. rq imports only that;
reaching past the boundary is an unresolved-import error.
Ideasets-as-public-API is undemonstrated today.
Absorbs half of former glue-semantics and module-interface.
- domain
- monorepo-architecture
- implementation
- module-surface.ts
- mechanism
- ideasets, imports, unresolved_import_diagnostics
- status
- done
- tier
- depth
test_proves_showcase
reqlan rq/site/site.rq
Depth. What this test actually proves.
Keep the intent of the former test-explanation page; upgrade it with a real
test-name anchor and the reverse direction from test file back to intent.
- domain
- testing
- implementation
- test-proves.ts
- mechanism
- test_name_anchors, comment_links, bidirectional_traceability
- status
- done
- tier
- depth
legacy_archaeology_showcase
reqlan rq/site/site.rq
Depth. Archaeology on inherited code.
An undocumented function, an rq-comment seeded into it, @ deprecated on the
old path, then Deprecation Impact listing everything that breaks.
Absorbs former scattered-docs page.
- domain
- legacy-migration
- implementation
- legacy-archaeology.ts
- mechanism
- comment_links, deprecated_attribute, deprecation_impact
- status
- done
- tier
- depth
graph_view_showcase
reqlan rq/site/site.rq
Depth. See the whole graph.
Needs real captured screenshots or a short loop from the actual Cytoscape
view — not fake ASCII arrows dressed as. rq.
Aligns with diagrams_are_never_dressed_as_code.
- domain
- extension-ui
- implementation
- graph-view.ts
- mechanism
- cytoscape_graph, status_tag_filters, indirect_reference_toggle
- status
- done
- tier
- depth
attribute_dialect_showcase
reqlan rq/site/site.rq
Depth. Attributes as a domain dialect.
The full attribute grammar: flags, negated flags, block values, nested and
named lists — forms nobody currently knows about.
Absorbs former arbitrary-attributes page.
- domain
- hardware-manufacturing
- implementation
- attribute-dialect.ts
- mechanism
- attribute_flags, negated_flags, block_values, nested_lists
- status
- done
- tier
- depth
antipatterns_showcase
reqlan rq/site/site.rq
Depth. Three ways to write. rq badly.
Data instead of pointers, prose restating code, one monolithic file.
Showing negative space is a taste signal.
Absorbs former data-not-ideas page; expands it.
- domain
- craft
- implementation
- antipatterns.ts
- mechanism
- pointers_not_data, editorial_taste
- status
- done
- tier
- depth
showcase_set
reqlan rq/site/site.rq
Ideaset (showcase_set)
absorbed_and_dropped
reqlan rq/site/site.rq
Absorbed into the eleven:
glue-semantics splits into firmware_cloud_contract_showcase and module_surface_showcase.
agentic-planning and feature-tracking fold into agent_context_showcase.
compliance becomes audit_trail_showcase.
scattered-docs becomes legacy_archaeology_showcase.
test-explanation upgrades into test_proves_showcase.
arbitrary-attributes upgrades into attribute_dialect_showcase.
static-connection upgrades into firmware_cloud_contract_showcase.
data-not-ideas expands into antipatterns_showcase.
graph-traversal upgrades into graph_view_showcase.
control-system-sequencing upgrades into interlock_showcase.
module-interface upgrades into module_surface_showcase.
Dropped:
todo-triage — too thin; triage is a byproduct of agent_context_showcase, not a page.
docs-attribute — sells tooling that does not exist; file refs to markdown belong inside other pages.
showcase_module
reqlan rq/site/site.rq
Showcases are standardised and typed in TS content objects.
Types live in types.ts.
Each showcase is its own file under showcases.
index.ts composes them in showcase_set order.
Each showcase file carries rq: comment references to its showcase idea
and to the product ideas it demonstrates.
Short version ( list card ): id, title, summary, tags, mechanism badge.
Long version ( detail page ): full blocks array including payoff.
Exist as a list page and as a full page per slug.
Routes: `/showcase/` and `/showcase/slug/` — static export.
Block kinds needed beyond today's code | features union:
callout — the one-sentence point of the page
exchange — query + response, terminal-styled
diagnostic — editor-style error with quick-fixes
diagram — visually distinct from code; never language- " rq "
caption / mechanism fields on the showcase object
Copy stays minimal and show-don ' t-tell, aligned with site copy rules.
- status
- done
- tests
- showcases.test.ts, showcases.test.ts:gives each showcase its own file with rq comment references
showcase_languages
reqlan rq/site/site.rq
. rq blocks use the custom site tokenizer.
Non-. rq blocks need Shiki coverage beyond today's ts / md / py —
add st, c, json, yaml for the flagship domains.
aligns with phase_1_parse_gate
phase_0_honesty_audit
reqlan rq/site/site.rq
In parallel with content rewrite. Fix what the honesty audit surfaced.
- status
- pending
- subreqs
- tags_list_indexing_gap { List-form tags parse but store true instead of a tag array in the idea extractor, so half of real-world tag usage never reaches the index. }, inbound_references_command { reqlan.openInboundReferencesSummary is declared in package.json with no handler. }, typo_cleanup { Former implementaion typo in this file — corrected to implementation. }
phase_1_parse_gate
reqlan rq/site/site.rq
Make dishonesty impossible.
Add a build step that runs the Langium parser over every language- " rq " block
in showcase content files and fails on parse errors or unresolved local refs.
Do this first so the rewrite cannot reintroduce the current problem.
Also expand Shiki language set per showcase_languages.
- priority
- P0
- status
- done
phase_2_content_schema
reqlan rq/site/site.rq
Extend ShowcaseBlock union and Showcase type per showcase_module.
Presentation polish can follow in phase_5_detail_layout; schema first.
- status
- done
phase_3_reqs_as_truth
reqlan rq/site/site.rq
This file is the source of truth: one idea per showcase with mechanism,
domain, and status; showcase_set listing them; refs into showcase content files.
Reqlan's own showcase plan is tracked in reqlan.
- status
- done
phase_4_write_the_eleven
reqlan rq/site/site.rq
Write the eleven, one at a time, each validated by phase_1_parse_gate
before moving on.
Flagships first — agent_context_showcase, interlock_showcase,
broken_links_showcase, firmware_cloud_contract_showcase —
so the format can be judged before committing to all eleven.
- plan
- order (
agent_context_showcase
interlock_showcase
broken_links_showcase
firmware_cloud_contract_showcase
audit_trail_showcase
module_surface_showcase
test_proves_showcase
legacy_archaeology_showcase
graph_view_showcase
attribute_dialect_showcase
antipatterns_showcase
) - status
- done
phase_5_detail_layout
reqlan rq/site/site.rq
Detail page layout: beats with captions, mechanism badges distinct from tags,
and cross-block highlighting of the shared identifier.
- status
- done
phase_6_capture_media
reqlan rq/site/site.rq
Capture real media from the extension for broken_links_showcase
( diagnostics / quick-fix ) and graph_view_showcase ( Cytoscape ).
- status
- done
showcase_plan
reqlan rq/site/site.rq
Ideaset (showcase_plan)
support_page
reqlan rq/site/support-page.rq
Rank actions by ease and likelihood to nudge. Star on GitHub is first.
Default view is a graph. Toggle Graph / Tiles / Table as icon buttons on the right of the header, with hover tooltips.
Graph: cola layout, settled on first paint to the visible window; copy has no graph coordinates; each node moves with its label; nodes are draggable; a drop keeps the new position; a drag does not start the action; all nodes offset slightly toward the cursor; nodes repel so some canvas edges stay open; action radius is impact × ease and stays latent to users; action nodes are solid and flat; each action links to a smaller passive original-group node in secondary colour ( advocacy, community, cite, contribute, sponsor ); group labels grow on group hover; labels do not overlap.
Hover on an action node shows a tooltip with the action blurb.
Star and sponsor tags are featured in the orange brand colour: the Star action, sponsor actions, and the Sponsor group.
Tiles: responsive flex layout.
Table: action and group only. Ease, impact, and score stay latent.
Action names use the aqua link colour in Graph, Tiles, and Table, including copy and share, except featured graph tags.
Each table row runs the same action as the graph and tiles: open a link, copy, or share.
Support via, in tile order:
- one click
- star on github
- share
- discord
- a minute
- cite
- issues
- post your certificate
- say something nice on the Visual Studio Marketplace
- say something nice on Open VSX
- FREE stickers: show the world you are a reqling, via phonebook sticker-form
- write
- reach out and send an email
- write a testimonial
- sponsor
- github sponsorship
- direct sponsorship
integrated with phonebook.
Copy lives in support.ts per copy.
The site exposes `/support/` as a statically generated page.
Sidebar nests Support section anchors as same-page children per sidebar_nav.
Landing nav graph includes Support as a page node per nav_graph.
- implementation
- page.tsx, SupportPage.tsx, SupportGraph.tsx, SupportTable.tsx, support.module.css, support.ts, support-action.ts, support-graph-cola.ts, nav.ts
- status
- done
show_dont_tell
reqlan rq/ui.rq
copy should be minimal and user facing.
no long lists, no avoidable labels.