axstack 0.38.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -66,7 +66,7 @@ You make decisions at holds and substantial-spec approval.
66
66
  Follow [getting started](docs/getting-started.md) for the full first-task journey
67
67
  and [guides](docs/guides.md) for features, reviews, watches, debugging and releases.
68
68
 
69
- ## What you can do (19 skills)
69
+ ## What you can do (20 skills)
70
70
 
71
71
  | Layer | Skill | What it does |
72
72
  | --- | --- | --- |
@@ -85,6 +85,7 @@ and [guides](docs/guides.md) for features, reviews, watches, debugging and relea
85
85
  | Operate | [axstack-watch](skills/axstack-watch/SKILL.md) | Observe or maintain an existing PR within its authority. |
86
86
  | Operate | [axstack-cleanup](skills/axstack-cleanup/SKILL.md) | Retire eligible completed agent resources. |
87
87
  | Operate | [axstack-relay](skills/axstack-relay/SKILL.md) | Send an explicit message or authorized notification. |
88
+ | Operate | [axstack-publish](skills/axstack-publish/SKILL.md) | Publish one checked Explain article in the explicitly authorized private or public mode. |
88
89
  | Understand | [axstack-research](skills/axstack-research/SKILL.md) | Answer one bounded question with sources. |
89
90
  | Understand | [axstack-scout](skills/axstack-scout/SKILL.md) | Gather codebase evidence for an agent across several areas. |
90
91
  | Understand | [axstack-explain](skills/axstack-explain/SKILL.md) | Explain a system and separate known behavior from gaps. |
@@ -235,15 +235,24 @@ This opt-in script changes only root `defaultModelSelection` in
235
235
  `~/.t3/userdata/settings.json`. Without a pool it changes only the instance
236
236
  among enabled accounts of the current Claude/Codex driver.
237
237
  `AXSTACK_SYNC_POOL` compares drivers by weekly clocks (>=604800s), without
238
- plan weights. Rotation needs a ten-point elapsed-minus-used pace lead;
239
- excluded/unauthorized/skipped current accounts can escape to known candidates.
240
- Any window at 95% or a reached limit excludes. Non-current absent credentials
238
+ plan weights. Weekly remaining quota is `R = 100 - used` for the selected
239
+ weekly window. Prefer the highest band: `R >= 15`, `10 <= R < 15`, then `R < 10`.
240
+ A higher band switches without a pace margin; within the same band, rotation
241
+ needs a ten-point elapsed-minus-used pace lead and the current account wins ties.
242
+ This also applies when every eligible account is below 10% remaining: known
243
+ usable quota stays usable, ranked by pace. Without a pool, only pace applies.
244
+ This is a best-effort weekly reserve preference, not a guaranteed budget for
245
+ future work. The current hard guard still excludes any window at 95% used
246
+ or a reached limit. Excluded/unauthorized/skipped current accounts can escape
247
+ to known candidates before the unknown hold; otherwise any unknown holds,
248
+ even below 10% remaining. No eligible candidate leaves the default untouched.
249
+ Non-current absent credentials
241
250
  exclude; malformed/unreadable credentials and unknown/stale usage hold.
242
251
  Cache expires after five minutes. Missing defaults stay untouched; OAuth tokens
243
252
  are never refreshed. Each host's pool uses only enabled, credentialed drivers:
244
253
 
245
254
  ```sh
246
- AXSTACK_SYNC_POOL=claudeAgent=claude-opus-5-5,codex=gpt-6.1-sol:xhigh \
255
+ AXSTACK_SYNC_POOL=claudeAgent=claude-opus-5-5,codex=gpt-6-astra:medium \
247
256
  bun ~/.agents/skills/axstack/scripts/sync-default.js --dry-run
248
257
  ```
249
258
 
@@ -258,6 +267,15 @@ A fsynced sibling preserves mode; original bytes are checked before rename and
258
267
  read back afterward. The accepted sub-ms T3 write race can lose an edit;
259
268
  read-back mismatch is an error.
260
269
 
270
+ Validate pool models and efforts against each host's catalog before activation.
271
+ Preserve that host's current Opus effort by including it explicitly when set;
272
+ the illustrative Claude entry above omits effort. If the current Codex default
273
+ still uses Sol, the driver performs a one-time same-account selection migration
274
+ to `gpt-6-astra:medium` during authorized host activation, saving rollback bytes
275
+ and verifying the write/readback. The helper does not enforce models when the
276
+ account stays selected. Only new chats use the changed default; running threads,
277
+ role routing, schedules and `roles.json` stay outside this policy.
278
+
261
279
  Under host-mutation authority, install and enable:
262
280
 
263
281
  ```sh
@@ -277,7 +295,7 @@ Override Bun/skills paths via `ExecStart`/`Environment` in
277
295
 
278
296
  ```ini
279
297
  [Service]
280
- Environment=AXSTACK_SYNC_POOL=claudeAgent=claude-opus-5-5,codex=gpt-6.1-sol:xhigh
298
+ Environment=AXSTACK_SYNC_POOL=claudeAgent=claude-opus-5-5,codex=gpt-6-astra:medium
281
299
  ```
282
300
 
283
301
  Reload after edits. Logout needs authorized linger; installation never activates units.
package/docs/workflows.md CHANGED
@@ -22,6 +22,9 @@ immediately before dispatch or account re-selection.
22
22
 
23
23
  Direct routes need no spec ceremony:
24
24
 
25
+ - [axstack-publish](../skills/axstack-publish/SKILL.md) publishes one Explain
26
+ HTML article in one explicitly authorized private or public mode through the
27
+ driver, after final-byte checks, independent review and live verification.
25
28
  - [axstack-verify](../skills/axstack-verify/SKILL.md) routes verification-skill
26
29
  creation and maintenance through Implement.
27
30
  A single-behavior check uses an existing `verify-<app>` skill or UI verification
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "axstack",
3
- "version": "0.38.0",
3
+ "version": "0.40.0",
4
4
  "description": "Axstack installer and setup CLI: installs owned chat skills and role data, configures supported harness settings, and checks T3 Code capabilities.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -39,17 +39,21 @@ export function decide(settings, usage, now, pool = null) {
39
39
  && Number.isFinite(window?.used) && Number.isFinite(window?.seconds) && window.seconds > 0
40
40
  && Number.isFinite(window?.resetAt) && window.resetAt > now
41
41
  && (!pooled || window.seconds >= 604800);
42
+ const remaining = known ? 100 - window.used : null;
42
43
  return { instanceId, state: excluded ? 'excluded' : known ? 'eligible' : 'unknown',
44
+ ...(pooled && { band: known ? remaining >= 15 ? 2 : remaining >= 10 ? 1 : 0 : null }),
43
45
  pace: known ? 100 * (1 - (window.resetAt - now) / (window.seconds * 1000)) - window.used : null };
44
46
  });
45
47
  const current = result.instances.find((entry) => entry.instanceId === from);
46
- const best = result.instances.filter((entry) => entry.state === 'eligible').sort((a, b) => b.pace - a.pace)[0];
48
+ const best = result.instances.filter((entry) => entry.state === 'eligible')
49
+ .sort((a, b) => (pooled ? b.band - a.band : 0) || b.pace - a.pace)[0];
47
50
  const excluded = !current || current.state === 'excluded';
48
51
  if (excluded && best) return updated(best, 'current-excluded');
49
52
  if (result.instances.some((entry) => entry.state === 'unknown')) return { ...result, reason: 'unknown' };
50
53
  if (!best) return { ...result, reason: 'no-eligible' };
51
- if (best.instanceId !== from && best.pace - current.pace >= 10) {
52
- return updated(best, 'pace');
54
+ const higherBand = pooled && best.band > current.band;
55
+ if (best.instanceId !== from && (higherBand || best.pace - current.pace >= 10)) {
56
+ return updated(best, higherBand ? 'reserve' : 'pace');
53
57
  }
54
58
  return { ...result, reason: 'margin' };
55
59
  }
@@ -0,0 +1,95 @@
1
+ ---
2
+ name: axstack-publish
3
+ description: When the user requests publication of an Explain HTML article, use axstack-publish to verify and publish that article in the explicitly authorized mode.
4
+ ---
5
+
6
+ # Publish
7
+
8
+ Publish an existing Explain HTML article through the notes CLI on the configured publish host.
9
+ The current T3 driver owns publication; workers return checked artifacts.
10
+ Load [Standing contracts](../axstack/references/contracts.md) and follow its
11
+ lifecycle pointers. Keep page bytes, checks and receipts in private run evidence.
12
+
13
+ ## 1. Bind the request
14
+
15
+ Read host-managed `~/.config/axstack/publish.json` containing string fields
16
+ `sshHost`, `publicOrigin` and `docsOrigin`.
17
+
18
+ ```json
19
+ {"sshHost":"<publish host>","publicOrigin":"<public HTTPS origin>","docsOrigin":"<docs HTTPS origin>"}
20
+ ```
21
+
22
+ Validate `sshHost` as `^[A-Za-z0-9][A-Za-z0-9.-]*$` and both origins as HTTPS
23
+ URL origins with no credentials, path, query or fragment.
24
+ Hold publication if the config is missing or invalid.
25
+ Never guess a publish host or either origin.
26
+ Keep these routing values host-managed; this config grants no publication authority.
27
+ Identify the Explain page by its exact bytes, byte count and SHA-256.
28
+ State the article, slug, mode (`private` or `public`) and target URL.
29
+ Public targets `<publicOrigin>/<slug>/`; private targets the
30
+ SlashDocs document URL at `docsOrigin` returned by the CLI.
31
+ For a new private document, state that origin and slug before publication and
32
+ record the allocated URL afterwards.
33
+ Require explicit authority for exactly one article and one mode per request.
34
+ Promotion, unpublish, reader changes and grant changes each need their own request.
35
+ Local creation or an earlier publication supplies no new publication authority.
36
+ If the request leaves the article or mode unclear, hold publication for clarification.
37
+
38
+ ## 2. Prepare the final artifact
39
+
40
+ For public mode, run the [Explain redaction check](../axstack-explain/SKILL.md#3-verify-and-deliver)
41
+ to remove private paths, IDs, credentials, prompts, messages and internal records.
42
+ For public mode, run Explain's [self-contained asset check](../axstack-explain/references/inline-pages.md#check-the-exact-bytes).
43
+ Reuse Explain's [page rules](../axstack-explain/references/inline-pages.md#page-rules)
44
+ and [Visual QA](../axstack-explain/references/visual-qa.md) for checks and verifier routing.
45
+
46
+ Add a standalone light/dark theme with inline defaults and `prefers-color-scheme`
47
+ so the article works outside T3; honor an explicit user theme request.
48
+ Theme adaptation changes bytes: save `final.html`, its byte count and SHA-256,
49
+ then rerun the referenced Explain page checks on these final bytes.
50
+ Require a fresh independent `axstack-explainer-review` on the final bytes.
51
+ Preview these exact bytes with Playwright MCP at 728px dark and 360px light;
52
+ record both screenshots and the Explain QA results.
53
+ Any subsequent byte change invalidates checks and review: repeat this step.
54
+ Hold publication while any required check or review is missing or failed.
55
+
56
+ ## 3. Publish from the driver
57
+
58
+ Publish only from the driver thread.
59
+ Use stdin only with no TTY and at most
60
+ 5,000,000 bytes (5 MB) of final HTML:
61
+
62
+ ```bash
63
+ ssh <publish host> notes publish --mode <mode> --slug <slug> < final.html
64
+ ```
65
+
66
+ Use the validated `sshHost`, validate the slug as `^[a-z0-9][a-z0-9-]{0,63}$`
67
+ and select one literal mode (`private` or `public`).
68
+ Use safely quoted arguments, never interpolate unchecked input into a shell.
69
+ Require exit zero and one JSON line containing `url`, `doc`, `version`, `sha256`.
70
+ Compare its SHA with the final artifact; a mismatch or ambiguous result holds
71
+ success reporting until reconciled with `ssh <publish host> notes status --slug <slug>`.
72
+ Require the returned URL's origin to match the configured origin for that mode.
73
+ Retain phase errors and pending state as unresolved evidence.
74
+
75
+ ## 4. Prove the live result and return
76
+
77
+ Verify the live URL in a real browser using Playwright MCP against the final SHA-256.
78
+ For public mode, verify an anonymous browser reads exact response bytes at
79
+ `<publicOrigin>/<slug>/` whose SHA-256 matches the final artifact.
80
+ Hash the response body bytes, rather than DOM serialization or rendered text.
81
+ For private mode, verify anonymous navigation reaches the SlashDocs sign-in page
82
+ leading to Dex and `notes status --slug <slug>` reports `published: true`, the
83
+ live version and SHA-256 that matches the final bytes.
84
+ Compare status's private version with the publish result; null live metadata
85
+ or a pending operation leaves verification unproven.
86
+ Reader-side reads are proven only by the separately authorized AC23 end-to-end
87
+ run; an anonymous redirect and CLI metadata do not prove a reader grant.
88
+ Return URL, version and SHA-256 with the live verification evidence or its hold.
89
+ Tell the user when `overwrote_external_edit` is true: publication replaced an
90
+ external edit, retained as an earlier SlashDocs version.
91
+
92
+ Agents never handle reader passwords.
93
+ Agents never run `notes reader show` or allocate a TTY (`-t` or `-tt` on SSH).
94
+ Reader and grant commands require their own request and secret-free non-TTY output.
95
+ The owner shares reader credentials separately from the article link.