| name | accelerate-learn |
| description | Update what the toolkit has learned about your site from A/B test results. Run periodically to improve future recommendations. |
| license | MIT |
| category | learning |
| parent | accelerate |
| disable-model-invocation | true |
Accelerate -- Update your site's learning journal
You read the site's completed A/B test results, classify each experiment into a canonical suggestion pattern, and update the site's learning journal so every other skill can tailor future recommendations to what has worked here.
This skill is read-only on WordPress. You never create, modify, or stop experiments. You write two local files only.
Step 1 -- Fetch site context
Call accelerate/get-site-context with include_blocks: false. You need site.name, site.theme (when present), and site.url to derive the site key.
Site key derivation rule
This is the canonical rule. No other skill implements its own version. The key identifies one site's design โ the thing we are optimizing โ so it combines the site's name, its active theme, and a stable hash of its URL.
Key format: <site-name-slug>-<theme-slug>-<url-hash>
Build each segment:
-
site-name-slug โ slugify site.name from get-site-context: lowercase, replace any run of non-alphanumeric characters with a single hyphen, strip leading/trailing hyphens. Example: "Example Co." -> example-co.
-
theme-slug โ slugify site.theme from get-site-context the same way, if it is present. If get-site-context does not return a theme (older plugin versions don't expose it), omit this segment entirely and fall back to <site-name-slug>-<url-hash>. Never error or block on a missing theme โ degrade gracefully.
-
url-hash โ a short, stable hash of the full site.url (including protocol, host, and port). Take the first 8 hex characters of its md5:
printf '%s' "<site.url>" | md5sum | cut -c1-8
Examples:
- name
"Example Co.", theme "twentytwentyfour", url https://www.example.com:8080 -> example-co-twentytwentyfour-3f9a2c11
- same site on a plugin that doesn't expose the theme ->
example-co-3f9a2c11
Why the theme is in the key: two sites can share a display name yet be different things we must not mix โ a staging copy and its production original commonly share a name but run different themes, and the design (the palette, typography, and section vocabulary we optimize) is tied to the theme, not the name. Including the theme keeps their journals and brand context separate. The URL hash separates same-named sites that share a host (e.g. several local sites on localhost), which a bare hostname cannot.
The bare hostname is banned as the key. Deriving the key from site.url's host alone collides every site that shares a host (all local sites resolve to localhost) and silently cross-contaminates their learning history. Always use the name + theme + hash format above.
No migration of old flat files. Earlier toolkit versions stored flat journal-<hostname>.* and brand-<hostname>.md files keyed on the hostname. Those are abandoned, not migrated โ on first run under the new key a fresh per-site journal starts. The old flat files can be deleted manually; the toolkit never reads them again.
Per-site store layout
Each site's files live in a per-site subdirectory keyed by the rule above:
~/.config/accelerate-ai-toolkit/sites/<key>/journal.json โ machine-readable journal (source of truth)
~/.config/accelerate-ai-toolkit/sites/<key>/journal.md โ human-readable summary, regenerated from the JSON
~/.config/accelerate-ai-toolkit/sites/<key>/brand.md โ brand context (design tokens; generated by accelerate-test)
~/.config/accelerate-ai-toolkit/sites/<key>/palette.json โ cached structure palette (surveyed by accelerate-test)
The shared ~/.config/accelerate-ai-toolkit/env credentials file stays where it is โ it is not per-site.
Step 2 -- List completed experiments
Call accelerate/list-experiments with:
status: "completed"
type: "all"
per_page: 100
page: 1
If the response's total exceeds 100, paginate: increment page and repeat until all experiments are fetched.
Collect the full list of completed experiments. Each item includes experiment_id, block_id, has_winner, winner_variant_index, annotations, started_at, ended_at.
Step 3 -- Get detailed results
For each experiment from step 2, call accelerate/get-experiment-results with experiment_id (not block_id). This returns the full variant metrics: impressions, conversions, conversion_rate, probability_to_beat_control, is_winner per variant.
Step 4 -- Read the existing journal
Read ~/.config/accelerate-ai-toolkit/sites/<key>/journal.json if it exists.
- File missing: Start with an empty journal structure. (This is expected on a site's first run under the new key โ old flat
journal-<hostname>.* files are not read or migrated.)
- Invalid JSON / parse error: Do not overwrite. Stop and tell the user: "Your learning journal appears to be corrupted. You can delete it and I'll rebuild from scratch, or restore it from a backup." Do not proceed.
schema_version is newer than 3: Stop and tell the user: "Your learning journal was created by a newer version of the toolkit. Please update the toolkit to read it." Do not proceed. (A schema_version of 1 is a pre-subdirectory flat journal and will not appear at this path; start fresh. A schema_version of 2 is a valid older journal โ read it, and add the iteration_counter field when you next write, see Step 6.)
- Valid: Parse and continue.
Step 5 -- Classify each experiment
For each experiment:
5a. Determine the pattern
Read annotations['toolkit:pattern'] from the experiment's annotations object.
- If present and matches a pattern_id in the taxonomy below: use that pattern.
- If present but not in the taxonomy: classify as
other and record the annotation value in the pattern's notes.
- If
annotations is missing or doesn't contain toolkit:pattern: classify as other.
No keyword fallback. No hypothesis text parsing. Classification is a pure dictionary lookup.
5b. Determine the outcome
| Condition | Result |
|---|
has_winner: true AND winner_variant_index > 0 | Win -- the tested change beat the control |
has_winner: true AND winner_variant_index == 0 | Loss -- the control won |
has_winner: false (experiment concluded without significance) | Inconclusive -- does not count as win or loss |
5c. Compute lift for wins
For wins: lift = ((winner_conversion_rate - control_conversion_rate) / control_conversion_rate) * 100. The control is always variant index 0. Store as a percentage.
Step 6 -- Merge into journal state
Update the iteration counter first. The journal tracks iteration_counter โ the number of experiments recorded in this site's auto-research sequence. It does double duty: it is the test number accelerate-test puts at the front of each experiment title ("#<n> <Block>", where n = iteration_counter + 1), and it indexes the x-axis of the auto-research progress chart โ so a card's #<n> and its point on the chart are the same number. Set iteration_counter to the count of completed experiments fetched in Step 2 (total_experiments_considered). This keeps the count stable across runs and global across rounds and blocks. If the existing journal had a higher counter than the fetched count (e.g. experiments created since the last list-experiments that haven't completed), keep the higher value โ the counter only ever moves forward.
For each pattern that has at least one experiment:
- Update
tests_won, tests_lost, tests_inconclusive
tests_total = tests_won + tests_lost + tests_inconclusive
hit_rate = tests_won / (tests_won + tests_lost) -- excludes inconclusive. If tests_won + tests_lost == 0, hit_rate is null.
avg_lift_percent = mean of all winning lifts for this pattern. null if no wins.
last_tested_at = most recent ended_at across all experiments for this pattern.
- Append to
compositions_tried โ for each experiment, add one entry recording the structural recombination tested (block_id, experiment_id, a short summary of the composition, the outcome, and ended_at). This is append-only: do not rewrite or drop prior entries. Carry forward and refine notes with any concept-level learning the stats don't capture, so the next run builds on this one.
- Apply the four-state classification:
| Status | Rule |
|---|
inconclusive | tests_won + tests_lost < 3 |
won | tests_won + tests_lost >= 3 AND hit_rate >= 0.75 |
lost | tests_won + tests_lost >= 3 AND hit_rate <= 0.25 |
mixed | tests_won + tests_lost >= 3 AND 0.25 < hit_rate < 0.75 |
The minimum threshold of 3 decisive tests (wins + losses, not counting inconclusive) is load-bearing. Do not lower it.
Step 7 -- Write the journal atomically
Write the JSON source of truth:
python3 -c "
import json, os, sys
data = json.loads(sys.argv[1])
path = os.path.expanduser(sys.argv[2])
tmp = path + '.tmp'
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(tmp, 'w') as f:
json.dump(data, f, indent=2)
f.write('\n')
os.chmod(tmp, 0o600)
os.rename(tmp, path)
" '<journal_json>' '~/.config/accelerate-ai-toolkit/sites/<key>/journal.json'
Then generate and write the markdown summary from the JSON (same atomic pattern).
JSON schema
{
"schema_version": 3,
"site": {
"key": "<site key โ see derivation rule>",
"name": "<from get-site-context>",
"theme": "<from get-site-context, or null if not exposed>",
"url": "<from get-site-context>"
},
"last_updated": "<ISO 8601 timestamp โ wall-clock UTC at the moment of the run>",
"iteration_counter": 0,
"stats": {
"total_experiments_considered": 0,
"concluded_with_winner": 0,
"concluded_without_winner": 0,
"patterns_with_signal": 0
},
"patterns": [
{
"pattern_id": "<from taxonomy>",
"display_name": "<from taxonomy>",
"status": "won|lost|mixed|inconclusive",
"tests_total": 0,
"tests_won": 0,
"tests_lost": 0,
"tests_inconclusive": 0,
"hit_rate": null,
"avg_lift_percent": null,
"last_tested_at": null,
"last_winning_block": null,
"compositions_tried": [
{
"block_id": null,
"experiment_id": null,
"summary": "<short plain-English description of the structural recombination tested โ e.g. 'hero + logo strip + single CTA'>",
"outcome": "win|loss|inconclusive",
"ended_at": null
}
],
"notes": null
}
]
}
Field notes:
iteration_counter is the site's running experiment count, used by accelerate-test as the test number at the front of each experiment title ("#<n> <Block>", where n = iteration_counter + 1) and as the x-axis index of the auto-research progress chart. It is global across rounds and blocks and only moves forward. See Step 6.
patterns_with_signal counts distinct patterns with at least one decisive test recorded (tests_won + tests_lost >= 1) โ regardless of the >=3 classification floor. total_experiments_considered counts every completed experiment fetched, including ones classified other.
compositions_tried is an append-only log of the structural recombinations that have been tested for this pattern โ which sections were composed together and how that variant did. It lets run N see what run N-1 already tried so later passes build on prior structure instead of re-testing settled compositions. Append one entry per experiment as you classify it (step 5); never rewrite history. Keep each summary short and human-readable.
notes is free-text carry-forward context for the next run: what has been learned about this pattern on this site that the stats alone don't capture (e.g. "outcome framing wins; social-proof framing has lost twice"). Update it, don't blank it.
Markdown format
Regenerated from the JSON on every run. The user reads this; no skill parses it.
# Learning journal -- [Site Name]
Last updated: [date]
Summary: [X] experiments analysed, [Y] with a clear winner, [Z] inconclusive.
## Patterns that win on your site
### [Display name]
- Won [N] of [M] tests ([hit_rate]%)
- Average improvement: +[lift]%
- Last tested: [date]
- Compositions tried: [short summaries of the structural recombinations and how each did]
## Patterns that haven't worked here
### [Display name]
- Won [N] of [M] tests ([hit_rate]%)
- Last tested: [date]
- [advisory note -- this is site-specific, not a universal rule]
## Mixed results
### [Display name]
- Won [N] of [M] tests
- Works sometimes, not a default
## Not enough data yet
### [Display name]
- [N] tests so far, need at least 3 decisive results before drawing conclusions
Step 8 -- Print summary to user
Short, marketer-friendly. Follow the output style guide (docs/output-style.md). Example:
Learning journal updated for [site name].
๐ด New this week: "Rewrite headline to match what visitors searched for" has now won 4 of 5 tests with an average +23% improvement. I'll lean on this when suggesting A/B tests.
๐ก Still building evidence: "Move the main button higher on the page" has 2 wins out of 3 -- one more test and I'll have a clearer picture.
๐ข Not working here: "Add urgency language to buttons" has lost all 3 tests. I'll stop leading with it unless you ask.
"Want me to suggest what to test next based on what we've learned?"
Hard rules for this output:
- Never show
pattern_id values. Always use display_name.
- Never say "journal file", "JSON", "schema", "parse", or "pattern taxonomy".
- Never recommend specific test ideas -- hand off to
accelerate-opportunities or accelerate-test.
- If no patterns have enough data yet, say so plainly and encourage patience.
Pattern taxonomy
These are the 15 canonical suggestion patterns. The pattern_id is the machine key; the display_name is what the user sees.
pattern_id | display_name |
|---|
headline_match_intent | Rewrite headline to match what visitors searched for |
headline_clarity | Rewrite headline for clarity |
cta_above_fold | Move the main call-to-action higher on the page |
cta_copy | Rewrite button or link text to be more specific |
social_proof | Add social proof near the call-to-action |
testimonial | Add a customer testimonial near the call-to-action |
urgency_copy | Add urgency or scarcity language |
simplify_hero | Simplify the hero section (remove clutter) |
pricing_display | Change how pricing is shown (default period, anchoring) |
personalize_referrer | Personalise content by traffic source |
personalize_geo | Personalise content by visitor location |
personalize_device | Personalise content by device type |
hero_image | Change the hero image |
form_fields | Change form field count or layout |
other | Other / unclassified |
This taxonomy is fixed. Do not invent new pattern_ids during a run. If an experiment doesn't match a known pattern, it goes to other. The taxonomy grows only in toolkit releases.
Rules
- Never create, modify, or stop experiments. This skill is read-only on WordPress.
- Never recommend specific test ideas in the summary. Hand off to other skills.
- Never overwrite a corrupted journal. Surface the error and let the user decide.
- All per-site files are
chmod 600. Same security posture as credentials.
- Old flat journals are abandoned, not migrated. A site's first run under the new key starts a fresh journal in its
sites/<key>/ subdirectory.
- Write atomically. Temp file + rename. Never write directly to the target path.
- Minimum 3 decisive tests before classification. The
inconclusive floor is non-negotiable.