quicue-kg is a CUE-native knowledge graph for tracking architectural [=decisions=], validated [=insights=], reusable [=patterns=], and [=rejected=] approaches. It uses CUE's type system and lattice-based unification to provide compile-time validation, conflict detection, and zero-infrastructure federation across project boundaries.
This specification defines the data model, directory layout, type constraints, [=KGIndex|aggregation
index=], and federation protocol for conforming .kg/ knowledge graphs.
This is an unofficial specification. It documents the quicue-kg framework as implemented
in the quicue.ca/kg@v0 CUE module. Feedback is welcome via the project's
issue tracker.
Software projects accumulate knowledge broader than source code: why a technology was chosen, what approaches were tried and abandoned, which [=patterns=] recur across repositories. This knowledge typically scatters across wikis, chat logs, and individual memory. When it is lost, teams re-explore failed paths and make decisions without context.
quicue-kg stores this knowledge as typed CUE [=entries=] in a
.kg/ directory alongside source code. The [[CUE]] language provides:
cue CLI. No database, no server.As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else is normative.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as described in [[RFC2119]].
A conforming knowledge graph is a knowledge graph in a .kg/ directory that:
package kg in all .cue files at the directory root.cue vet without errors when evaluated against the
quicue.ca/kg schemas..cue files in subdirectories (CUE packages
are directory-scoped; see ).A conforming processor is a tool that:
@type field in all serialization formats..kg/ directory.{[string]: true} used to represent set membership.
Provides O(1) lookup, deduplication, and clean unification across projects.
Used for related, used_in, and similar fields.kg: expands to
https://quicue.ca/kg#. It is used in @type fields
and as a CURIE prefix in JSON-LD exports (see
extensions).This section is non-normative. It summarizes CUE language features that are essential to understanding this specification. Readers familiar with CUE may skip this section. For a complete reference, see [[CUE]].
#Decision is itself a value — a partially-specified
struct. Writing core.#Decision & {id: "ADR-001", ...} is
not "instantiating a type" but unifying two values. The result
must satisfy all constraints from both sides. This is why schema validation
and data authoring are the same operation.#).# are definitions.
By default, definitions are closed: they reject undeclared
fields. However, adding ... makes a definition
open — it accepts additional fields beyond those
declared in the schema. The quicue-kg core types are open: required fields
are validated, but users may add domain-specific fields freely. Definitions
are not emitted during export (cue export).
Regular identifiers are open and are emitted._)._ are hidden — not emitted
during export. The index uses _index as a hidden field so
that cue export .kg/ doesn't dump the entire aggregation.
To export it, use cue export .kg/ -e _index.summary."proposed" | "accepted" | "deprecated" | "superseded" is
a disjunction — the value must be exactly one of the listed
options. This is how CUE expresses enumerated types. Any value outside the
set is a validation error.& (unification) to compose constraints:
string & !="" means "a string that is not empty."
[...string] & [_, ...] means "a list of strings with at
least one element" (_ matches any value).
=~"^ADR-\\d{3}$" constrains a string by regex."high" | "medium" | "low" can later be refined to
"high" but can never be widened to accept
"maybe". This is the mechanism behind
progressive refinement: knowledge
accumulates, it cannot silently disappear.
A conforming knowledge graph resides in a .kg/ directory at the root
of a project. All CUE files MUST be at the directory root level — CUE packages are
directory-scoped, meaning files in subdirectories constitute separate package instances
even if they declare the same package name.
project/
.kg/
cue.mod/
module.cue # Module declaration
pkg/
quicue.ca/
kg/ # Schema dependency (symlink or registry)
decisions.cue # Entry files (package kg)
insights.cue
rejected.cue
patterns.cue
index.cue # aggregate.#KGIndex (recommended)
The .kg/cue.mod/module.cue file MUST declare a CUE module. The module
name SHOULD follow the pattern {project-domain}/.kg but MAY use any
valid CUE module identifier.
// .kg/cue.mod/module.cue module: "local.project/kg" language: version: "v0.15.4" source: kind: "self"
The quicue-kg schemas MUST be available to the CUE evaluator. This MAY be achieved through any of the following mechanisms:
CUE_REGISTRY='quicue.ca=ghcr.io/quicue/cue-modules,registry.cue.works'
and run cue mod tidy..kg/cue.mod/pkg/quicue.ca/kg/ pointing to a local checkout of the
quicue-kg repository.
Every .cue file at the root of the .kg/ directory MUST
declare package kg. Files MUST NOT be placed in subdirectories.
package kg
import "quicue.ca/kg/core@v0"
d001: core.#Decision & {
id: "ADR-001"
title: "Use CUE for configuration"
// ...
}
Entries SHOULD be organized by type into separate files for readability.
| File | Contents | Status |
|---|---|---|
decisions.cue | All #Decision entries | RECOMMENDED |
insights.cue | All #Insight entries | RECOMMENDED |
rejected.cue | All #Rejected entries | RECOMMENDED |
patterns.cue | All #Pattern entries | RECOMMENDED |
index.cue | aggregate.#KGIndex | RECOMMENDED |
A conforming knowledge graph MAY combine all entries into a single file. File boundaries are not semantically significant — CUE evaluates all files in a package as a single logical unit.
Core types define the four fundamental [=entry=] categories that every conforming
knowledge graph MUST support. They are defined in the quicue.ca/kg/core@v0
package and have no external dependencies.
All core types share the following conventions:
@type field with a fixed kg:-prefixed value.id with a regex pattern, or name
for patterns.related? field using the struct-as-set idiom for cross-referencing.string & !=""....) — required fields are validated, but
users MAY add domain-specific fields. People are their own lexicographers.#Decision)
A Decision records an architecture decision with mandatory rationale and
consequences. Decisions follow a status lifecycle from proposed through
accepted to eventual deprecated or superseded.
| Field | Type | Constraint | Required | Description |
|---|---|---|---|---|
@type |
string |
Fixed: "kg:Decision" |
Yes | Type discriminator. |
id |
string |
=~"^ADR-\d{3}$" |
Yes | Unique identifier (e.g., ADR-001). |
title |
string |
Non-empty | Yes | Human-readable summary of the decision. |
status |
string |
"proposed" | "accepted" | "deprecated" | "superseded" |
Yes | Current lifecycle status. |
date |
string |
=~"^\d{4}-\d{2}-\d{2}$" |
Yes | Date the decision was made (ISO 8601). |
context |
string |
Non-empty | Yes | What prompted this decision. |
decision |
string |
Non-empty | Yes | What was decided. |
rationale |
string |
Non-empty | Yes | Why this decision was made. |
consequences |
[...string] |
At least one element | Yes | What follows from this decision. |
supersedes |
string |
=~"^ADR-\d{3}$" |
No | ID of the decision this supersedes. |
appliesTo |
[...{...}] |
No | Structured scope annotations (open). | |
related |
{[string]: true} |
Struct-as-set | No | Cross-references to other entries. |
d001: core.#Decision & {
id: "ADR-001"
title: "Use CUE for configuration"
status: "accepted"
date: "2026-01-15"
context: "Need a type-safe configuration language."
decision: "Use CUE for all configuration and schema definitions."
rationale: "CUE provides compile-time validation and lattice-based types."
consequences: ["All config files are .cue", "Validated with cue vet"]
}
#Insight)
An Insight records a validated discovery with mandatory evidence and an
explicit confidence level. The method field tracks how the
insight was discovered, supporting reproducibility.
| Field | Type | Constraint | Required | Description |
|---|---|---|---|---|
@type | string |
Fixed: "kg:Insight" |
Yes | Type discriminator. |
id | string |
=~"^INSIGHT-\d{3}$" |
Yes | Unique identifier. |
statement | string |
Non-empty | Yes | What was discovered. |
evidence | [...string] |
At least one element | Yes | Supporting evidence. |
method | string |
"cross_reference" | "gap_analysis" | "statistics" | "experiment" | "observation" |
Yes | Discovery method. |
confidence | string |
"high" | "medium" | "low" |
Yes | How certain we are. |
discovered | string |
ISO 8601 date | Yes | When discovered. |
implication | string |
Non-empty | Yes | What this means for the project. |
action_items | [...string] |
No | Suggested follow-up actions. | |
related | {[string]: true} |
Struct-as-set | No | Cross-references. |
#Rejected)
A Rejected [=entry=] records an approach that was tried and abandoned.
The alternative field is REQUIRED — every rejection must suggest
what to do instead. This prevents the "we tried that" conversation loop by turning
dead ends into redirects.
| Field | Type | Constraint | Required | Description |
|---|---|---|---|---|
@type | string |
Fixed: "kg:Rejected" |
Yes | Type discriminator. |
id | string |
=~"^REJ-\d{3}$" |
Yes | Unique identifier. |
approach | string |
Non-empty | Yes | What was tried. |
reason | string |
Non-empty | Yes | Why it failed. |
date | string |
ISO 8601 date | Yes | When rejected. |
alternative | string |
Non-empty | Yes | What to do instead. |
related | {[string]: true} |
Struct-as-set | No | Cross-references. |
#Pattern)
A Pattern captures a reusable problem/solution pair with cross-project
usage tracking. The used_in field uses the struct-as-set idiom,
which means federating two projects that both use the same pattern automatically
produces the union of their used_in sets.
| Field | Type | Constraint | Required | Description |
|---|---|---|---|---|
@type | string |
Fixed: "kg:Pattern" |
Yes | Type discriminator. |
name | string |
Non-empty | Yes | Pattern name (also serves as ID). |
category | string |
Non-empty | Yes | Classification category. |
problem | string |
Non-empty | Yes | What problem this solves. |
solution | string |
Non-empty | Yes | How to solve it. |
context | string |
Non-empty | Yes | When to apply this pattern. |
used_in | {[string]: true} |
Struct-as-set | Yes | Projects using this pattern. |
example | string |
No | Usage example. | |
related | {[string]: true} |
Struct-as-set | No | Cross-references. |
The KGIndex is the computed aggregation of all [=entries=] in a knowledge graph. It collects entries by type, computes summary counts, and derives cross-cutting views (decisions by status, insights by confidence). All computed fields use CUE comprehensions — they are never hand-maintained.
The index is defined in the quicue.ca/kg/aggregate@v0 package.
| Field | Type | Computed | Description |
|---|---|---|---|
project | string |
No | Project name (user-provided). |
decisions | {[string]: #Decision} |
No | All decision entries, keyed by ID. |
insights | {[string]: #Insight} |
No | All insight entries, keyed by ID. |
rejected | {[string]: #Rejected} |
No | All rejected entries, keyed by ID. |
patterns | {[string]: #Pattern} |
No | All pattern entries, keyed by name. |
summary | struct |
Yes | Counts: total_decisions, total_insights,
total_rejected, total_patterns, total. |
by_status | struct |
Yes | Decisions grouped by status value. |
by_confidence | struct |
Yes | Insights grouped by confidence level. |
// .kg/index.cue
package kg
import "quicue.ca/kg/aggregate@v0"
_index: aggregate.#KGIndex & {
project: "my-project"
decisions: { "ADR-001": d001 }
insights: { "INSIGHT-001": i001 }
rejected: { "REJ-001": r001 }
patterns: { "struct-as-set": p_struct_as_set }
}
// Export: cue export .kg/ -e _index.summary --out json
Federation merges multiple knowledge graphs across project boundaries.
Unlike systems that require shared databases or SPARQL endpoints, quicue-kg federation
uses CUE unification as its merge primitive. The transport layer is
git clone. The conflict detector is the CUE type checker.
A conforming processor discovers knowledge graphs by walking the filesystem
looking for .kg/cue.mod/module.cue:
.kg/cue.mod/module.cue..kg/ directory with cue vet.# Discover all .kg/ directories under ~/projects/ kg fed ~/projects/ # Load specific directories kg --dir ~/api/.kg --dir ~/web/.kg --dir ~/infra/.kg index
Federation merging follows CUE unification semantics:
related, used_in) merge via union.Conflicts are features, not bugs. A type error during federation means two projects assert contradictory facts. The error requires explicit human resolution — no silent last-write-wins.
A conforming processor MAY support remote sources specified as git URLs.
Remote sources are shallow-cloned, the .kg/ directory is located,
and entries are loaded and merged as with local sources.
# Local + remote kg --dir .kg --dir https://github.com/org/other-project.git search "caching" # The --dir flag is repeatable. All commands support it. kg --dir ~/a/.kg --dir ~/b/.kg --dir ~/c/.kg serve
Write operations (add) target the first --dir value only.
Knowledge graph entries MAY contain sensitive architectural decisions, such as security architecture choices, authentication strategy rationale, or infrastructure topology information. Implementors SHOULD consider:
.kg/ directories in version control inherit the repository's
access control. If the repository is public, all entries are public.context and rationale fields of #Decision
entries may inadvertently expose threat models or security assumptions.
Knowledge graph entries MUST NOT contain credentials, secrets, API keys, tokens, or
other authentication material. The .kg/ directory is for structural
and architectural knowledge, not operational secrets.
Federation exposes project metadata across organizational boundaries:
used_in fields reveal which projects use which patterns.Organizations SHOULD establish federation policies that define which projects may be federated and with whom.
The core specification intentionally covers only the four fundamental entry types. Domain-specific extensions are defined in companion packages:
| Package | Types | Purpose |
|---|---|---|
quicue.ca/kg/ext@v0 |
#Derivation, #Context, #Workspace |
Data pipeline provenance, project identity, multi-repo topology |
quicue.ca/kg/aggregate@v0 |
#KGLint, #Provenance, #Annotations,
#DatasetEntry, #FederatedCatalog |
Quality checks, W3C projections (PROV-O, Web Annotation, DCAT) |
Extension types are OPTIONAL. Core types MUST NOT import from extension packages.
Extensions MAY import from core.
Normative CUE type definitions. Canonical source:
quicue.ca/kg/core@v0.
#Decision: {
"@type": "kg:Decision"
id: =~"^ADR-\\d{3}$"
title: string & !=""
status: "proposed" | "accepted" | "deprecated" | "superseded"
date: =~"^\\d{4}-\\d{2}-\\d{2}$"
context: string & !=""
decision: string & !=""
rationale: string & !=""
consequences: [...string] & [_, ...]
supersedes?: =~"^ADR-\\d{3}$"
appliesTo?: [...{...}]
related?: {[string]: true}
...
}
#Insight: {
"@type": "kg:Insight"
id: =~"^INSIGHT-\\d{3}$"
statement: string & !=""
evidence: [...string] & [_, ...]
method: "cross_reference" | "gap_analysis" | "statistics" | "experiment" | "observation"
confidence: "high" | "medium" | "low"
discovered: =~"^\\d{4}-\\d{2}-\\d{2}$"
implication: string & !=""
action_items?: [...string]
related?: {[string]: true}
...
}
#Rejected: {
"@type": "kg:Rejected"
id: =~"^REJ-\\d{3}$"
approach: string & !=""
reason: string & !=""
date: =~"^\\d{4}-\\d{2}-\\d{2}$"
alternative: string & !=""
related?: {[string]: true}
...
}
#Pattern: {
"@type": "kg:Pattern"
name: string & !=""
category: string & !=""
problem: string & !=""
solution: string & !=""
context: string & !=""
example?: string
used_in: {[string]: true}
related?: {[string]: true}
...
}
A minimal but complete .kg/ directory using all four core types.
package kg
import "quicue.ca/kg/core@v0"
d001: core.#Decision & {
id: "ADR-001"
title: "Use CUE for configuration"
status: "accepted"
date: "2026-01-15"
context: "Need a type-safe configuration language."
decision: "Use CUE for all configuration and schema definitions."
rationale: "Compile-time validation and lattice-based type system."
consequences: ["All config files are .cue, validated with cue vet"]
}
package kg
import "quicue.ca/kg/core@v0"
i001: core.#Insight & {
id: "INSIGHT-001"
statement: "CUE unification is sufficient for cross-project merging"
evidence: ["Federated 5 .kg/ directories without conflicts"]
method: "experiment"
confidence: "high"
discovered: "2026-02-10"
implication: "No external query engine needed for federation."
related: {"ADR-001": true}
}
package kg
import "quicue.ca/kg/core@v0"
r001: core.#Rejected & {
id: "REJ-001"
approach: "Store knowledge graph in SQLite"
reason: "Adds runtime dependency. Loses CUE type safety."
date: "2026-01-10"
alternative: "Use flat CUE files in .kg/ with cue vet for validation."
}
package kg
import "quicue.ca/kg/core@v0"
p_struct_as_set: core.#Pattern & {
name: "Struct-as-Set"
category: "data-modeling"
problem: "Arrays allow duplicates and lack O(1) membership testing."
solution: "Use {[string]: true} for set-valued fields."
context: "Any field representing set membership."
used_in: {"my-project": true}
}
package kg
import "quicue.ca/kg/aggregate@v0"
_index: aggregate.#KGIndex & {
project: "my-project"
decisions: { "ADR-001": d001 }
insights: { "INSIGHT-001": i001 }
rejected: { "REJ-001": r001 }
patterns: { "struct-as-set": p_struct_as_set }
}
# Validate
cue vet .kg/
# Export summary
cue export .kg/ -e _index.summary --out json
# {"total_decisions":1,"total_insights":1,"total_rejected":1,"total_patterns":1,"total":4}
# Federate with another project
kg --dir .kg --dir ~/other-project/.kg graph
This section is non-normative.
A rejection without an alternative is a dead end with no signpost. By requiring
alternative, every dead end becomes a redirect.
{"a": true} & {"b": true} yields
{"a": true, "b": true}.CUE packages are directory-scoped. Files in subdirectories are separate packages, even with the same package name. The flat directory requirement ensures all entries share a single package scope, enabling cross-referencing and aggregation.