-
Notifications
You must be signed in to change notification settings - Fork 7
Decisions Ledger and Learning
The .ux/decisions.jsonl ledger is the substrate v3.0's intelligence loop runs on. Every recommend, design, lint, evolve, and synthesize call appends one line. The recommender consults the log on the next call and bumps candidates that have shipped clean before. Cold-start safe, fully offline.
Column names are a public contract. Renaming is a breaking change. New columns can be added with default null for compat-readers.
{
"_v": 1,
"ts": 1727380123.456,
"command": "design",
"brief_id": "ab12cd34e5f67890",
"context_hash": "f0e1d2c3b4a59687",
"industry": "fintech-payments",
"ui_type": "dashboard",
"mode": "brand_anchor",
"picked_brand": "stripe",
"picked_style": "swiss-grid",
"picked_palette": "stripe-cool",
"axes": {"warmth": 0.35, "contrast": 0.55, ...},
"lint_score": 92,
"lint_high": 0,
"lint_med": 1,
"lint_low": 3,
"artifact_path": "/path/to/out.html",
"user_accepted": true,
"duration_ms": 1240
}-
.ux/decisions.jsonl— per-project (gitignored by convention via.gitignore) -
~/.uxskill/decisions.jsonl— per-user, cross-project memory
Both files are append-only JSONL. Best-effort writes — filesystem errors are swallowed (e.g., read-only mount, permission denied). A failed write never blocks the command.
-
UXSKILL_NO_LOG=1env var disables all writes -
--no-logCLI flag has the same effect -
Scope.PROJECTwrites only to project file -
Scope.USERwrites only to user file -
Scope.BOTHwrites both (default)
The recommender's re-rank reads from whichever scope is enabled, so disabling logging means the system stops learning (the trade-off is yours).
Each of the 5 ranking lanes (_lane_style, _lane_palette, _lane_type, _lane_motion, _lane_brands) now:
- Computes the manifest-only score per candidate.
- Drops candidates with forbidden penalty (score < -50).
- Reads the decisions ledger filtered by
(industry, ui_type). -
Counts wins per candidate id (decisions where
lint_score >= 80ANDuser_accepted = true). - Bumps each candidate's score by +5 per matching prior win.
- Re-sorts the resulting list.
Below 3 matching priors for the (industry, ui_type) bucket, the re-ranker is a no-op. This prevents the system from "learning" from N=1 noise. Below threshold, the recommender behaves exactly like v2.0.
-
lint_score >= 80— a "clean enough" decision worth learning from -
user_accepted = true— explicit signal that the user agreed with the output -
(industry, ui_type)bucket — keeps learning context-specific
The combination is conservative on purpose. The recommender doesn't pretend to learn aesthetic preferences from random taste signals. It learns "for this (industry, ui_type), these specific tokens reliably ship clean."
# Disable logging for this run
UXSKILL_NO_LOG=1 uxskill lint <file>
# or
uxskill lint <file> --no-log
# Inspect what's been logged
uxskill stats --decisions
# Local HTML dashboard
uxskill stats --html
# → writes .ux/stats.html — open in browserOver stdio, the same data is exposed:
-
ux_decisions_query— filter by industry / ui_type / command / min_score / accepted_only -
ux_decisions_stats— aggregate (total, by_command, top_brands, lint_score_median, acceptance_rate)
from engine.decisions import record, read_all, query, stats, Scope
record({
"command": "design",
"industry": "fintech-payments",
"ui_type": "dashboard",
"picked_brand": "stripe",
"lint_score": 92,
"user_accepted": True,
}, scope=Scope.BOTH)
winners = query(
industry="fintech-payments",
ui_type="dashboard",
min_score=80,
accepted_only=True,
)
# → list[dict] of past wins
agg = stats(scope=Scope.PROJECT)
# → {total_decisions, by_command, top_brands, lint_score_median, ...}- No raw user prompts
- No external IDs
- No network/IP/user-agent data
- No machine fingerprint
- No analytics events to any service
- No "telemetry uploaded to vendor"
It's a file. On your disk. Owned by you. That's the entire surface.
"Decision ledger is the real backbone — but currently underpowered. You added engine/decisions/ JSONL, but you are not explicitly using it as retrieval memory, ranking bias, failure correction signal. Right now it's a log, not a learning substrate. That's the biggest missed opportunity in v2.1."
v3.0 fixed exactly this. The recommender now reads the ledger and biases ranking. Closed loop.
- v3-The-Brain
- Synthesizer-7-axes
- All-22-Commands — every command that writes to the ledger