@miroshnik/elves 0.0.0 → 2026.1018.1
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/AGENTS.md +310 -0
- package/README.md +344 -0
- package/bin/ai-dev.ts +7 -0
- package/bin/elves.ts +2847 -0
- package/bin/shims/timeout +113 -0
- package/claude/CLAUDE.md +71 -0
- package/dist/github/scripts/github.js +3428 -0
- package/dist/spec/scripts/architecture.js +628 -0
- package/dist/spec/scripts/eslint-config.js +54 -0
- package/dist/spec/scripts/harness-qzb932c8.js +959 -0
- package/dist/spec/scripts/harness-v9s1v9w3.js +16045 -0
- package/dist/spec/scripts/harness.js +53 -0
- package/dist/spec/scripts/knip-hints.cjs +34 -0
- package/docs/ci-concurrency.md +82 -0
- package/docs/cloud-sessions.md +204 -0
- package/docs/judgment.md +81 -0
- package/docs/parallel-checkouts.md +220 -0
- package/docs/pr-checks.md +117 -0
- package/docs/testing.md +304 -0
- package/package.json +70 -1
- package/skills/ci-wait/SKILL.md +180 -0
- package/skills/ci-wait/scripts/wait-ci.sh +377 -0
- package/skills/dashboard/SKILL.md +212 -0
- package/skills/dashboard/scripts/dashboard.ts +912 -0
- package/skills/dashboard/scripts/sessions.ts +772 -0
- package/skills/est/SKILL.md +222 -0
- package/skills/est/reference.md +381 -0
- package/skills/est/scripts/est.ts +4867 -0
- package/skills/github/SKILL.md +206 -0
- package/skills/github/locales/en.json +449 -0
- package/skills/github/locales/ru.json +449 -0
- package/skills/github/reference.md +1073 -0
- package/skills/github/scripts/github.ts +4390 -0
- package/skills/github/scripts/locale.ts +495 -0
- package/skills/github/scripts/package.json +3 -0
- package/skills/slot/SKILL.md +145 -0
- package/skills/slot/scripts/package.json +3 -0
- package/skills/slot/scripts/slot.ts +279 -0
- package/skills/spec/SKILL.md +247 -0
- package/skills/spec/canon.md +219 -0
- package/skills/spec/checks.md +709 -0
- package/skills/spec/ci.md +378 -0
- package/skills/spec/migration.md +125 -0
- package/skills/spec/reference.md +889 -0
- package/skills/spec/scripts/architecture.ts +839 -0
- package/skills/spec/scripts/c4.ts +184 -0
- package/skills/spec/scripts/eslint-config.ts +82 -0
- package/skills/spec/scripts/harness.ts +1483 -0
- package/skills/spec/scripts/knip-hints.cjs +34 -0
- package/skills/spec/scripts/knip-hints.d.cts +17 -0
- package/skills/spec/scripts/package-run.ts +22 -0
- package/skills/spec/scripts/package.json +3 -0
- package/skills/spec/scripts/spec-break.ts +232 -0
- package/skills/spec/scripts/spec-claims.ts +198 -0
- package/skills/spec/scripts/spec-diff.ts +1111 -0
- package/skills/spec/scripts/spec-doc.ts +744 -0
- package/skills/spec/scripts/spec-exceptions.ts +233 -0
- package/skills/spec/scripts/spec-publish.ts +214 -0
- package/skills/spec/scripts/spec-run.ts +235 -0
- package/skills/spec/scripts/spec-shard.ts +267 -0
- package/skills/spec/scripts/speclib.ts +826 -0
- package/skills/spec/scripts/vendor/babel-parser.LICENSE +19 -0
- package/skills/spec/scripts/vendor/babel-parser.cjs +14615 -0
- package/skills/spec/scripts/vendor/babel-parser.d.cts +3 -0
- package/skills/task-env/SKILL.md +229 -0
- package/skills/task-env/proxy/compose.yaml +48 -0
- package/skills/task-env/reference.md +246 -0
- package/skills/task-env/scripts/task-env.ts +981 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
marksIn2,
|
|
3
|
+
exceptionsIn2,
|
|
4
|
+
exceptionFiles2,
|
|
5
|
+
invariant2,
|
|
6
|
+
examples2,
|
|
7
|
+
eslintLinter2,
|
|
8
|
+
source2,
|
|
9
|
+
sources2,
|
|
10
|
+
codeFiles2,
|
|
11
|
+
codeOnly2,
|
|
12
|
+
disablesIn2,
|
|
13
|
+
lintExceptions2,
|
|
14
|
+
testFileIn2,
|
|
15
|
+
journal2,
|
|
16
|
+
resetJournal2,
|
|
17
|
+
trace2,
|
|
18
|
+
sequence2,
|
|
19
|
+
deadCode2,
|
|
20
|
+
ENV_SERVICE2,
|
|
21
|
+
configGet2,
|
|
22
|
+
envNamesIn2,
|
|
23
|
+
envNamesInCode2,
|
|
24
|
+
dotenvNames2,
|
|
25
|
+
envVars2
|
|
26
|
+
} from "./harness-v9s1v9w3.js";
|
|
27
|
+
import"./harness-qzb932c8.js";
|
|
28
|
+
export {
|
|
29
|
+
ENV_SERVICE2 as ENV_SERVICE,
|
|
30
|
+
codeFiles2 as codeFiles,
|
|
31
|
+
codeOnly2 as codeOnly,
|
|
32
|
+
configGet2 as configGet,
|
|
33
|
+
deadCode2 as deadCode,
|
|
34
|
+
disablesIn2 as disablesIn,
|
|
35
|
+
dotenvNames2 as dotenvNames,
|
|
36
|
+
envNamesIn2 as envNamesIn,
|
|
37
|
+
envNamesInCode2 as envNamesInCode,
|
|
38
|
+
envVars2 as envVars,
|
|
39
|
+
eslintLinter2 as eslintLinter,
|
|
40
|
+
examples2 as examples,
|
|
41
|
+
exceptionFiles2 as exceptionFiles,
|
|
42
|
+
exceptionsIn2 as exceptionsIn,
|
|
43
|
+
invariant2 as invariant,
|
|
44
|
+
journal2 as journal,
|
|
45
|
+
lintExceptions2 as lintExceptions,
|
|
46
|
+
marksIn2 as marksIn,
|
|
47
|
+
resetJournal2 as resetJournal,
|
|
48
|
+
sequence2 as sequence,
|
|
49
|
+
source2 as source,
|
|
50
|
+
sources2 as sources,
|
|
51
|
+
testFileIn2 as testFileIn,
|
|
52
|
+
trace2 as trace
|
|
53
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* knip-hints — a knip reporter for the harness's `deadCode`: configuration hints (a redundant `ignore`, an `entry`
|
|
3
|
+
* without matches, a redundant workspace) as a JSON line
|
|
4
|
+
* `{ "configurationHints": [{ type, identifier, workspace, file? }] }`. knip's `json` reporter doesn't print them,
|
|
5
|
+
* and `--treat-config-hints-as-errors` gives only an exit code — the hints themselves aren't visible.
|
|
6
|
+
*
|
|
7
|
+
* knip --reporter json --reporter .agents/skills/spec/scripts/knip-hints.cjs
|
|
8
|
+
*
|
|
9
|
+
* The second output line is its own: `deadCode` joins both. CommonJS, not TypeScript: the harness takes the file
|
|
10
|
+
* path (`report.file`) with a static import — `import.meta` in a module that Playwright and Jest load as CommonJS is
|
|
11
|
+
* a syntax error (tests/standards/harness-load); knip loads it under both Node and Bun. Types — `knip-hints.d.cts`.
|
|
12
|
+
*/
|
|
13
|
+
"use strict";
|
|
14
|
+
|
|
15
|
+
const path = require("node:path");
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Hints as knip collected them (`ReporterOptions.configurationHints`): an identifier may be a regex (an `ignore`
|
|
19
|
+
* pattern), a file path is absolute; `--no-config-hints` — the project itself opted out of hints.
|
|
20
|
+
*/
|
|
21
|
+
function report(options) {
|
|
22
|
+
const hints = options.isDisableConfigHints
|
|
23
|
+
? []
|
|
24
|
+
: options.configurationHints.map((h) => ({
|
|
25
|
+
type: h.type,
|
|
26
|
+
identifier: h.identifier instanceof RegExp ? h.identifier.source.replaceAll("\\/", "/") : String(h.identifier),
|
|
27
|
+
workspace: h.workspaceName ?? ".",
|
|
28
|
+
...(h.filePath ? { file: path.relative(options.cwd, path.resolve(options.cwd, h.filePath)).split(path.sep).join("/") } : {}),
|
|
29
|
+
}));
|
|
30
|
+
process.stdout.write(JSON.stringify({ configurationHints: hints }) + "\n");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
report.file = __filename;
|
|
34
|
+
module.exports = report;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# CI: parallel tasks — the rule and workflow fragments
|
|
2
|
+
|
|
3
|
+
A reference for the "CI: parallel tasks" section of `AGENTS.md`: here is the
|
|
4
|
+
full rule and ready-made fragments to copy.
|
|
5
|
+
|
|
6
|
+
## Rule
|
|
7
|
+
|
|
8
|
+
Every branch and every PR runs independently; only the branch's own stale run
|
|
9
|
+
is cancelled. Serialization — only where there is a shared resource (a deploy
|
|
10
|
+
environment, a shared database, an external service with limits). One queue
|
|
11
|
+
for all of CI is not a solution: it slows down every task, and without
|
|
12
|
+
`queue: max` it also cancels pending runs. Workflow fragments — below.
|
|
13
|
+
|
|
14
|
+
- **Branches and PRs run in parallel:** a `concurrency` group by PR number or
|
|
15
|
+
branch, `cancel-in-progress: true`.
|
|
16
|
+
- **`main`, tags and manual runs are never cancelled:** their runs deploy, and
|
|
17
|
+
an interrupted deploy is worse than an extra run. Instead of cancelling —
|
|
18
|
+
`queue: max` (by default GitHub keeps one pending run and evicts it with the
|
|
19
|
+
next one: a third merge in a row would cancel the second).
|
|
20
|
+
- **Deploy — a queue per environment:** the deploy job has the group
|
|
21
|
+
`deploy-<env>`, shared by all workflows of the repository, and `queue: max`.
|
|
22
|
+
Without it the job queue evicts pending jobs, just as at the workflow level:
|
|
23
|
+
at run time the environment's third deploy job cancels the waiting second
|
|
24
|
+
one, and a manual run cancels a waiting tag deploy.
|
|
25
|
+
- **CI and deploy — in different workflows:** `queue: max` is incompatible
|
|
26
|
+
with `cancel-in-progress: true`. In one workflow —
|
|
27
|
+
`cancel-in-progress: ${{ github.event_name == 'pull_request' }}` without
|
|
28
|
+
`queue: max`: the deploy won't be interrupted, but a pending run may be
|
|
29
|
+
evicted.
|
|
30
|
+
- **The agent doesn't cancel or re-run others' runs** (`gh run cancel` and
|
|
31
|
+
`gh run rerun` — only its own run on its own branch). Waiting for its own
|
|
32
|
+
checks and merging — the "Git, PRs and merging" section of `AGENTS.md`.
|
|
33
|
+
|
|
34
|
+
## Workflow fragments
|
|
35
|
+
|
|
36
|
+
Checked against the GitHub Actions documentation ("Control the concurrency of
|
|
37
|
+
workflows and jobs"): `queue: max` allows up to 100 pending runs (beyond that
|
|
38
|
+
they are cancelled) and is incompatible with `cancel-in-progress: true`;
|
|
39
|
+
`false` is the default; `queue` also works on `jobs.<id>.concurrency`, which
|
|
40
|
+
is supported on a job with `uses:` (reusable workflow) too;
|
|
41
|
+
`cancel-in-progress` accepts expressions; a deploy job's group is shared
|
|
42
|
+
across the repository, so the same name in different workflows gives one
|
|
43
|
+
queue.
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
# ci.yml — branches and PRs in parallel; a branch's stale run is cancelled
|
|
47
|
+
on:
|
|
48
|
+
pull_request:
|
|
49
|
+
concurrency:
|
|
50
|
+
group: ci-${{ github.event.pull_request.number || github.ref }}
|
|
51
|
+
cancel-in-progress: true
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
# cd.yml — main, tags, manual runs: nothing is cancelled, runs wait in a queue
|
|
56
|
+
on:
|
|
57
|
+
push:
|
|
58
|
+
branches: [main]
|
|
59
|
+
tags: ['v*']
|
|
60
|
+
workflow_dispatch:
|
|
61
|
+
concurrency:
|
|
62
|
+
group: cd-${{ github.ref }}
|
|
63
|
+
queue: max
|
|
64
|
+
jobs:
|
|
65
|
+
deploy-dev:
|
|
66
|
+
concurrency:
|
|
67
|
+
group: deploy-dev # environment = queue, shared by all workflows
|
|
68
|
+
queue: max # the next deploy doesn't evict a pending one
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If CI and deploy are in one workflow (they can't be split right now):
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
concurrency:
|
|
75
|
+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
76
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
A running deploy on `main` won't be interrupted this way, but of three merges
|
|
80
|
+
in a row the third run evicts the pending second one — the third deploys
|
|
81
|
+
everything together, and the second commit is left without a CI status on
|
|
82
|
+
`main`.
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Claude Code cloud session
|
|
2
|
+
|
|
3
|
+
Reference for the cloud-session line in `AGENTS.md`. A cloud session is
|
|
4
|
+
Claude Code on claude.ai/code, including one started from the phone app: a
|
|
5
|
+
temporary container into which only the project repository is cloned.
|
|
6
|
+
A dispatcher's executor can be one (`AGENTS.md`, "Session and branch — one
|
|
7
|
+
task"): at most 3 subagents and 5 cloud sessions at once, the owner's number
|
|
8
|
+
replaces either — a cloud session's container doesn't load the machine.
|
|
9
|
+
|
|
10
|
+
## What it sees
|
|
11
|
+
|
|
12
|
+
Only the project repository. The canon, the skills and the agent's memory of
|
|
13
|
+
the user's machine (`~/.agents`, `~/.claude`) aren't there: the flow comes
|
|
14
|
+
from the project's **`SessionStart` hook** — `.claude/settings.json`, which
|
|
15
|
+
`install` and `update` put into a thin project (#610). The cloud runs a
|
|
16
|
+
project's hooks — not `~/.claude/settings.json` — after Claude Code starts,
|
|
17
|
+
on every start and resume. With `CLAUDE_CODE_REMOTE=true` the hook does what
|
|
18
|
+
an environment's setup script did (#555), without the owner's step: `npm i -g
|
|
19
|
+
bun@latest @miroshnik/elves && elves install -g`, then `check --hook` into the
|
|
20
|
+
context; outside the cloud it exits at once. The canon already on the machine
|
|
21
|
+
— nothing to install; a failed step — a line with its command, code 0. An
|
|
22
|
+
Elves clone carries the hook in its commit: Bun, zsh for its tests
|
|
23
|
+
(`tests/capabilities/agent-shell`) and the flow from the clone itself —
|
|
24
|
+
`install -g --link`, the branch's canon, no npm. A fresh start of the clone's
|
|
25
|
+
hook with zsh in place took 4.4 s (2026-10-17: npm about 3 s, `check --hook`
|
|
26
|
+
about 1 s); without zsh `apt-get update` and its install add about 6 s.
|
|
27
|
+
|
|
28
|
+
- `bun@latest` — the image's Bun lags behind a project's `packageManager`
|
|
29
|
+
(1.4.2 on 2026-10-16, without the `bun check` of 1.4.3): npm's global
|
|
30
|
+
directory comes before `~/.bun/bin` in the image's `PATH`, while `bun
|
|
31
|
+
upgrade` in the session gets 403 from GitHub.
|
|
32
|
+
- **No apt lists in the image** (2026-10-17): `apt-get install zsh` alone —
|
|
33
|
+
"Unable to locate package"; `apt-get update` first. `--force-confold` — the
|
|
34
|
+
image has its own `/etc/zsh/zshrc`: without it dpkg asks whether to replace
|
|
35
|
+
it and fails without a terminal (#598).
|
|
36
|
+
- **npm has no release yet** (2026-10-17): `@miroshnik/elves` there is the
|
|
37
|
+
`0.0.0` stub without the `elves` command, so a thin project's hook prints
|
|
38
|
+
"the flow isn't installed (exit 127)" until CI publishes a release (README,
|
|
39
|
+
"Installation" — the owner's step). The clone's hook doesn't need npm.
|
|
40
|
+
- **The setup script** is optional, a faster start: the environment caches
|
|
41
|
+
its result for about 7 days, and the hook then installs nothing. Network
|
|
42
|
+
access — Trusted (the default), about 7 s:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm i -g bun@latest @miroshnik/elves && elves install -g
|
|
46
|
+
# an Elves clone's environment: zsh for its tests (tests/capabilities/agent-shell), CI installs it too
|
|
47
|
+
apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y -o Dpkg::Options::=--force-confold zsh
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- **The project's version** — `@miroshnik/elves` in its `devDependencies`,
|
|
51
|
+
only from npm: bun installs it through the session's proxy, `github:` in
|
|
52
|
+
the session is 403. It works in the project language, just like a local
|
|
53
|
+
session: `language` in `.agents/elves.json`, which comes with the clone.
|
|
54
|
+
- **A thin project behind** — updated in the session's task, as locally:
|
|
55
|
+
`bunx @miroshnik/elves update` raises the package version, a few lines into
|
|
56
|
+
the task's branch; a project without the hook yet gets it the same way, and
|
|
57
|
+
until then — `check` by hand.
|
|
58
|
+
- **No machine hook:** the cloud doesn't read `~/.claude/settings.json`; the
|
|
59
|
+
project's hook runs `check --hook` instead, without `github task resume`
|
|
60
|
+
(Projects are closed there). An environment without Bun or zsh all the same
|
|
61
|
+
— `check` names it with a `cloud environment:` line and the command, which
|
|
62
|
+
the session runs itself.
|
|
63
|
+
- **A project with a copy of the flow** loads the canon twice in the cloud —
|
|
64
|
+
the copy's `.claude/rules` and the setup script's — until its move to the
|
|
65
|
+
thin project; a copy gets no project hook, nothing names it.
|
|
66
|
+
|
|
67
|
+
**What is visible at the start** — checked from inside a cloud session
|
|
68
|
+
(2026-10-17, Claude Code 2.1.302, #610), which itself started without the
|
|
69
|
+
hook:
|
|
70
|
+
|
|
71
|
+
- Skills `install -g --link` put into `~/.claude/skills` mid-session —
|
|
72
|
+
Claude Code picked them up at once (the skills list in the context
|
|
73
|
+
changed).
|
|
74
|
+
- Rules `~/.claude/rules/elves*.md` written mid-session didn't reach the
|
|
75
|
+
context of that turn. By the diagnostics log (`$CLAUDE_CODE_DIAGNOSTICS_FILE`)
|
|
76
|
+
Claude Code reads memory files at the start of a user turn
|
|
77
|
+
(`cli_turn_started`, then `memory_files_completed` with `file_count`), so
|
|
78
|
+
the rules the hook writes before the first turn should load.
|
|
79
|
+
- The clone hook's command, run as Claude Code runs it (`sh -c`, a fresh
|
|
80
|
+
`HOME`): code 0, the output is `check --hook`'s; outside the cloud — no
|
|
81
|
+
output.
|
|
82
|
+
|
|
83
|
+
Still to check — in the first cloud session of the clone after the merge:
|
|
84
|
+
the hook's output in the context; `memory_files_completed` at the first
|
|
85
|
+
`cli_turn_started` has `file_count` 3 (the clone's `.claude/CLAUDE.md` and
|
|
86
|
+
both rules); ask the agent to quote a rule from `AGENTS.md` and list the
|
|
87
|
+
skills — `est`, `spec`, `ci-wait` must be there. The rules didn't load — the
|
|
88
|
+
hook prints the canon (#610, question 2).
|
|
89
|
+
|
|
90
|
+
## What the cloud lacks (checked 2026-09-25, 2026-10-17)
|
|
91
|
+
|
|
92
|
+
- **GitHub GraphQL** is closed by the session proxy ("use the REST API").
|
|
93
|
+
REST — only `repos/{owner}/{repo}/…` paths of the session's repositories;
|
|
94
|
+
**Projects v2** (`users/…/projectsV2…`, `orgs/…`) — 403. Project fields
|
|
95
|
+
(`Status`, `Estimate, h`, `Actual, h`, tokens, cost) can't be set from the
|
|
96
|
+
cloud; `est` computes neither the estimate nor the actual.
|
|
97
|
+
- **Writing to the repository** (push, editing issues, comments, PRs) — only
|
|
98
|
+
if the Claude GitHub App has access to the repository. No access — 403
|
|
99
|
+
("Resource not accessible by integration", "Claude doesn't have GitHub
|
|
100
|
+
access"): the user installs or reconnects the app
|
|
101
|
+
(claude.ai → Settings → Connectors → GitHub; github.com/apps/claude).
|
|
102
|
+
- **The cloud assigns the branch** (`claude/<slug>`) and forbids pushing to
|
|
103
|
+
others without explicit permission. A branch by the `<type>/<N>-<slug>`
|
|
104
|
+
convention — create it after asking the user at the start, together with
|
|
105
|
+
the task's questions.
|
|
106
|
+
- **The session title** (`set_session_title`) is stored on the server and
|
|
107
|
+
doesn't get into the transcript: `est` links cloud work to the task only by
|
|
108
|
+
the branch, the only `#N` in the first prompt (section "The brief") and
|
|
109
|
+
commit hashes.
|
|
110
|
+
- **The container is temporary**: anything unpushed is lost.
|
|
111
|
+
- **Root:** the session runs as uid 0 — `chmod` doesn't deny writes. The
|
|
112
|
+
flow's write-denial tests (`install`, `slot`) run the checked process as
|
|
113
|
+
`nobody` (`setpriv`); a test relying on permissions without that is green
|
|
114
|
+
or red for the wrong reason.
|
|
115
|
+
- **GitHub Actions job logs** over REST (`actions/jobs/<id>/logs`) — 403: the
|
|
116
|
+
answer redirects to blob storage the proxy doesn't let through;
|
|
117
|
+
`get_job_logs` of the GitHub MCP works.
|
|
118
|
+
- **GitHub search** (`search/issues`) — 403 ("sessions are bound to their
|
|
119
|
+
configured repositories"): the duplicate check before a new task — by
|
|
120
|
+
listing `repos/{owner}/{repo}/issues`.
|
|
121
|
+
- **The `github` skill's scripts** — `task show`, `task answer`, `task new`
|
|
122
|
+
over the repository's REST (#603): without the project — `task new` names
|
|
123
|
+
Status and the estimate in a line for a local session; the rest refuse
|
|
124
|
+
(`CLAUDE_CODE_REMOTE`). The scenarios section — by hand over REST (`PATCH
|
|
125
|
+
repos/…/issues/N`). The proxy ends a description it writes with its
|
|
126
|
+
"Generated by Claude Code" signature after `---` (doesn't add a second one):
|
|
127
|
+
the questions section ends at `---`, the signature isn't its last question's.
|
|
128
|
+
|
|
129
|
+
## The brief — `#` only for its task
|
|
130
|
+
|
|
131
|
+
The cloud names the branch itself (`claude/<slug>`), so `est` links a session
|
|
132
|
+
to its task by the first prompt: it takes every `#N` of the whole prompt —
|
|
133
|
+
with the "Background (from the session that started this one)" block the
|
|
134
|
+
harness puts before the task — and links only by exactly one (#594). Whoever
|
|
135
|
+
writes a cloud session's first prompt — the owner or a dispatcher session —
|
|
136
|
+
names only its task with `#`, in the background too; the epic, other tasks and
|
|
137
|
+
PRs — a number without `#` ("epic 40", "tasks 41 and 43") or a title. The
|
|
138
|
+
executor prompt of `github task queue` has `(epic #M)`: fine for a subagent,
|
|
139
|
+
whose assignment `est` reads by the word "Task"; a cloud executor's brief is
|
|
140
|
+
`github task queue --assignment <N> --cloud` — whole (`task queue` refuses
|
|
141
|
+
in the cloud), the epic and numbers in the title without `#`. Two `#N` —
|
|
142
|
+
`est fact <N>` in the cloud prints `Actual unavailable (cloud)` though the
|
|
143
|
+
transcript is in the container.
|
|
144
|
+
|
|
145
|
+
## Closing a task from the cloud
|
|
146
|
+
|
|
147
|
+
`github task close` refuses in the cloud (GitHub Projects are unavailable)
|
|
148
|
+
and prints the same steps:
|
|
149
|
+
|
|
150
|
+
1. `est fact <N>` computes this session's part of the actual from its
|
|
151
|
+
transcript in the container (linking — the branch `<type>/<N>-…` or the
|
|
152
|
+
only `#N` in the first prompt, section "The brief"; the session's PR in
|
|
153
|
+
its own repository, by the clone's `origin`, doesn't break it, #617) and
|
|
154
|
+
prints an `Actual (cloud)` comment
|
|
155
|
+
with hours, tokens, a link to the session and a part marker — post it to
|
|
156
|
+
the issue with a GitHub tool. Project fields (`Actual, h`, tokens, cost)
|
|
157
|
+
are set by the next local session: `est fact <N> --write` or
|
|
158
|
+
`est fact --sweep --write` adds the cloud part to the local work. The
|
|
159
|
+
transcript didn't link — `Actual unavailable (cloud)`, and a local session imports the session's events via the browser
|
|
160
|
+
(the `est` skill, "Cloud session").
|
|
161
|
+
2. `Status` = Done is set by the project's built-in workflow "Item closed"
|
|
162
|
+
(whether it is enabled — a local session checks with the `github` skill);
|
|
163
|
+
not enabled — ask the user to set the status.
|
|
164
|
+
3. Epic refresh — by a subagent with a fresh context, as locally (issues,
|
|
165
|
+
sub-issues, milestones are available through the repository's REST); what
|
|
166
|
+
can't be done from the cloud (project fields, estimates of new tasks via
|
|
167
|
+
`est`) — into a State comment for the local session.
|
|
168
|
+
|
|
169
|
+
**A local dispatcher learns of it by the task's closing** (#609): a cloud
|
|
170
|
+
session can't message the local one that started it. `send_message` to a
|
|
171
|
+
local session is refused — `elevated_session_untrusted_device`, then "target
|
|
172
|
+
session could not be verified" on every retry (checked 2026-10-17);
|
|
173
|
+
`create_trigger` (`persistent_session_id`) and `get_session` don't take a
|
|
174
|
+
local session's id (`local_…`); `ListAgents` in the cloud sees no sessions of
|
|
175
|
+
the owner's machine; the owner's approval on a trusted device
|
|
176
|
+
(`confirm_repository_trust` with the `content_digest` of such a refusal —
|
|
177
|
+
these carried none) is, by the tool's description, for one cloud session,
|
|
178
|
+
i.e. per executor. So the brief tells the executor not to message the
|
|
179
|
+
dispatcher and not to archive its session, and the dispatcher waits for the
|
|
180
|
+
merge's `Closes #N`: `ci-wait issue <N>` as its own background command; PASS
|
|
181
|
+
— `github task close <N>` locally (the actual with `--write`, `Status`, the
|
|
182
|
+
merged `claude/<slug>` branch), then archiving the executor's session where
|
|
183
|
+
it has the tool (till then its transcript may be needed for `est`); TIMEOUT —
|
|
184
|
+
the task's questions section and State comment, the executor's session, the
|
|
185
|
+
wait again. After the app restarts the queue's `=` line names the wait.
|
|
186
|
+
|
|
187
|
+
## Push failed — a local session finishes
|
|
188
|
+
|
|
189
|
+
A cloud session that can't write hands the work over as files: the branch —
|
|
190
|
+
`git bundle` or `git format-patch --stdout` (a session attachment), answers
|
|
191
|
+
to questions — in the PR text or the final message. A local session, by the
|
|
192
|
+
task number:
|
|
193
|
+
|
|
194
|
+
1. Answers from the cloud — into the task's questions section
|
|
195
|
+
(`github task answer`), before code.
|
|
196
|
+
2. The branch — from a fresh `origin/main`:
|
|
197
|
+
`git fetch <file>.bundle <branch>:<branch>` or `git am <file>.mbox`; if the
|
|
198
|
+
cloud didn't start from it — rebase.
|
|
199
|
+
3. Review the diff and the same checks as CI **on this machine**: the cloud
|
|
200
|
+
is Linux, and platform differences (symlinks via `/var` → `/private/var`
|
|
201
|
+
on macOS) aren't visible there.
|
|
202
|
+
4. Then as usual: PR, green checks, merge, actual. The actual sees only the
|
|
203
|
+
local part of the work — add the line `Reason: missed work: …`
|
|
204
|
+
(reason: missed work) with a link to the cloud session.
|
package/docs/judgment.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Judgment and edits: where a mistake looks like a result — for "Tests and code"
|
|
2
|
+
|
|
3
|
+
Reference for the "Tests and code" section of `AGENTS.md`: the full rules and
|
|
4
|
+
examples (made up). What the four have in common: such a mistake is caught
|
|
5
|
+
neither by green checks nor by plausible numbers — only by the question of
|
|
6
|
+
what the result, the label or the request is really about.
|
|
7
|
+
|
|
8
|
+
## A mistake disguised as an outcome
|
|
9
|
+
|
|
10
|
+
The most dangerous defect of a plan is one whose symptom matches one of the
|
|
11
|
+
expected results: neither a check nor reading the numbers will catch it — the
|
|
12
|
+
outcome is plausible, and it will be read as the answer.
|
|
13
|
+
|
|
14
|
+
- **Before a measurement or a launch** (an experiment, a campaign, a load
|
|
15
|
+
run, a data migration) — write down the expected outcomes and for each one
|
|
16
|
+
ask: which of our mistakes would give exactly the same result?
|
|
17
|
+
- **There is one — a separate check before the launch,** not an analysis
|
|
18
|
+
after it: after the launch its outcome can no longer be told apart from the
|
|
19
|
+
answer.
|
|
20
|
+
- **An unchecked number is marked in the table itself** (in the cell, in the
|
|
21
|
+
row), not in a footnote: it may reverse the conclusion, and not everyone
|
|
22
|
+
reads footnotes.
|
|
23
|
+
|
|
24
|
+
Example. A bid of "0.60" in an ad account whose currency turns out to be not
|
|
25
|
+
the euro but one where 0.60 is next to nothing: there are no impressions, and
|
|
26
|
+
it will be read as "no demand". The check before the launch — the account's
|
|
27
|
+
currency and a test impression.
|
|
28
|
+
|
|
29
|
+
## A label is a claim
|
|
30
|
+
|
|
31
|
+
A label, a unit and a condition ("per month", "excl. VAT", "per user") claim
|
|
32
|
+
what the number under them means. A request to "make the labels (units,
|
|
33
|
+
conditions) the same" — first check against the source of each number that
|
|
34
|
+
they are about the same thing, and only then change the text.
|
|
35
|
+
|
|
36
|
+
- About the same thing — I align them.
|
|
37
|
+
- About different things — I say so plainly and give options: recalculate to
|
|
38
|
+
one meaning, honestly different labels, leave as is.
|
|
39
|
+
- Green checks (a snapshot, a text lint, a "labels match" test) compare
|
|
40
|
+
labels with each other, not with what the number means: the same label over
|
|
41
|
+
different numbers passes them all.
|
|
42
|
+
|
|
43
|
+
Example. One table says "Revenue, ₽", another "Revenue, thousand ₽"; the
|
|
44
|
+
request is for identical labels. First — what units the numbers are really
|
|
45
|
+
in: otherwise one of the labels becomes false by a factor of a thousand.
|
|
46
|
+
|
|
47
|
+
## Editing exactly what was named
|
|
48
|
+
|
|
49
|
+
Asked for order, alignment or formatting — I change only that: not the
|
|
50
|
+
content, not the composition, not the neighboring wording. The rule isn't
|
|
51
|
+
only for an autonomous routine ("What I do without asking and what needs a
|
|
52
|
+
yes" in `AGENTS.md`): any request names its own scope.
|
|
53
|
+
|
|
54
|
+
- **The named change requires deleting an entity** (a row, a field, a
|
|
55
|
+
section, a test) — the solution is wrong, not the entity redundant: I look
|
|
56
|
+
for another one.
|
|
57
|
+
- **The requirements really are incompatible** — I say so and let the person
|
|
58
|
+
choose, rather than resolving it by deletion.
|
|
59
|
+
|
|
60
|
+
Example. The request is to align pricing cards by height; one is taller than
|
|
61
|
+
the rest by one item. Removing the item is no longer alignment: height by the
|
|
62
|
+
longest one, wrapping into two columns or shortening the text — the human
|
|
63
|
+
chooses.
|
|
64
|
+
|
|
65
|
+
## "It doesn't reproduce for me"
|
|
66
|
+
|
|
67
|
+
A discrepancy between what the human sees and what I see is a claim about my
|
|
68
|
+
tool, not about the product. I don't argue, but:
|
|
69
|
+
|
|
70
|
+
- name what I measured with and where: browser and version, window width,
|
|
71
|
+
data and account, environment (local, preview, production), cache;
|
|
72
|
+
- ask for the human's conditions and reproduce in them;
|
|
73
|
+
- still didn't reproduce — I say what was checked and ask for what's missing
|
|
74
|
+
(a screenshot, an address, a time), rather than closing it as "not a bug".
|
|
75
|
+
|
|
76
|
+
Example. The human sees buttons overlapping each other, for me they're even:
|
|
77
|
+
I looked at a width of 1440 px in a clean profile, the human — at 390 px with
|
|
78
|
+
a long name in the header. One product in the conversation, two tools.
|
|
79
|
+
|
|
80
|
+
"Didn't help" after a fix is a different rule: the "Production and debugging"
|
|
81
|
+
section of `AGENTS.md` (production facts, not a third reproduction).
|