🛟 Updated.
c441b24 parent: bae2487 renamed
.github.bak/workflows/release.yml +0 -0 | similarity index 100% | ||
| rename from .github/workflows/release.yml | ||
| rename to .github.bak/workflows/release.yml |
| similarity index 100% | |||
| rename from .github/workflows/release.yml | |||
| rename to .github.bak/workflows/release.yml |
modified
.gitignore +4 -0 | @@ -16,3 +16,7 @@ docker-agent | ||
| 16 | 16 | release |
| 17 | 17 | .claude |
| 18 | 18 | .vibe |
| 19 | +.ci.cd.token.env | |
| 20 | +.release.env | |
| 21 | +backup | |
| 22 | +.backup | |
| @@ -16,3 +16,7 @@ docker-agent | |||
| 16 | release | 16 | release |
| 17 | .claude | 17 | .claude |
| 18 | .vibe | 18 | .vibe |
| 19 | +.ci.cd.token.env | ||
| 20 | +.release.env | ||
| 21 | +backup | ||
| 22 | +.backup | ||
modified
.tickets/issues/0195-sign-the-macos-binary-of-mini-me.yaml +24 -3 | @@ -6,7 +6,7 @@ author: | ||
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-11-07T05:28:39.000Z |
| 9 | -updatedAt: 2026-11-07T05:46:16.000Z | |
| 9 | +updatedAt: 2026-11-07T08:07:23.000Z | |
| 10 | 10 | labels: |
| 11 | 11 | - kind::chore |
| 12 | 12 | epic: Release & distribution |
| @@ -61,10 +61,31 @@ tasks: | ||
| 61 | 61 | createdAt: 2026-11-07T05:28:39.000Z |
| 62 | 62 | - id: 4 |
| 63 | 63 | title: Check carefully whether the API already allows publishing an asset to a release |
| 64 | - state: open | |
| 64 | + state: closed | |
| 65 | 65 | priority: urgent |
| 66 | 66 | author: |
| 67 | 67 | name: k33g |
| 68 | 68 | email: ph.charriere@gmail.com |
| 69 | 69 | createdAt: 2026-11-07T05:46:16.000Z |
| 70 | -comments: [] | |
| 70 | + updatedAt: 2026-11-07T08:07:23.000Z | |
| 71 | + closedAt: 2026-11-07T08:07:23.000Z | |
| 72 | +comments: | |
| 73 | + - id: 1 | |
| 74 | + author: | |
| 75 | + name: k33g | |
| 76 | + email: ph.charriere@gmail.com | |
| 77 | + createdAt: 2026-11-07T08:07:23.000Z | |
| 78 | + body: | | |
| 79 | + Checked against the OpenAPI document, the MCP tools, the CLI source and real calls. | |
| 80 | + | |
| 81 | + - `/api/v1` creates, updates and deletes a release with a personal token, but has no upload route. Nor do the MCP server and the CLI. | |
| 82 | + - The `/gh` shim can upload, for the job's `GITHUB_TOKEN` only. A personal token gets 401 `Bad credentials` there (tried on read requests). | |
| 83 | + - A CI job on a temporary branch works: `demo-ci-local.sh` builds on the machine and `demo-publish-release.sh` publishes. Tried on `demo-002`: 6 files uploaded with the exact local sizes, branch deleted. | |
| 84 | + | |
| 85 | + Traps: | |
| 86 | + - **A published prerelease becomes `/releases/latest`.** `demo-001` broke `latest/download/SHA256SUMS` for about 30 seconds. Use a draft until the release is the real one. | |
| 87 | + - Tags are immutable: a push cannot delete one, only the repository's Tags page can. | |
| 88 | + - An asset with an existing name is refused with a 422, and no route to delete an asset was found, so replacing a binary is still open. | |
| 89 | + - The binaries go through git on the temporary branch: 148 MB per run with all platforms. | |
| 90 | + | |
| 91 | + The feature request text is in `demo-rickub-feature-request.txt`. | |
| @@ -6,7 +6,7 @@ author: | |||
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-11-07T05:28:39.000Z | 8 | createdAt: 2026-11-07T05:28:39.000Z |
| 9 | -updatedAt: 2026-11-07T05:46:16.000Z | 9 | +updatedAt: 2026-11-07T08:07:23.000Z |
| 10 | labels: | 10 | labels: |
| 11 | - kind::chore | 11 | - kind::chore |
| 12 | epic: Release & distribution | 12 | epic: Release & distribution |
| @@ -61,10 +61,31 @@ tasks: | |||
| 61 | createdAt: 2026-11-07T05:28:39.000Z | 61 | createdAt: 2026-11-07T05:28:39.000Z |
| 62 | - id: 4 | 62 | - id: 4 |
| 63 | title: Check carefully whether the API already allows publishing an asset to a release | 63 | title: Check carefully whether the API already allows publishing an asset to a release |
| 64 | - state: open | 64 | + state: closed |
| 65 | priority: urgent | 65 | priority: urgent |
| 66 | author: | 66 | author: |
| 67 | name: k33g | 67 | name: k33g |
| 68 | email: ph.charriere@gmail.com | 68 | email: ph.charriere@gmail.com |
| 69 | createdAt: 2026-11-07T05:46:16.000Z | 69 | createdAt: 2026-11-07T05:46:16.000Z |
| 70 | -comments: [] | 70 | + updatedAt: 2026-11-07T08:07:23.000Z |
| 71 | + closedAt: 2026-11-07T08:07:23.000Z | ||
| 72 | +comments: | ||
| 73 | + - id: 1 | ||
| 74 | + author: | ||
| 75 | + name: k33g | ||
| 76 | + email: ph.charriere@gmail.com | ||
| 77 | + createdAt: 2026-11-07T08:07:23.000Z | ||
| 78 | + body: | | ||
| 79 | + Checked against the OpenAPI document, the MCP tools, the CLI source and real calls. | ||
| 80 | + | ||
| 81 | + - `/api/v1` creates, updates and deletes a release with a personal token, but has no upload route. Nor do the MCP server and the CLI. | ||
| 82 | + - The `/gh` shim can upload, for the job's `GITHUB_TOKEN` only. A personal token gets 401 `Bad credentials` there (tried on read requests). | ||
| 83 | + - A CI job on a temporary branch works: `demo-ci-local.sh` builds on the machine and `demo-publish-release.sh` publishes. Tried on `demo-002`: 6 files uploaded with the exact local sizes, branch deleted. | ||
| 84 | + | ||
| 85 | + Traps: | ||
| 86 | + - **A published prerelease becomes `/releases/latest`.** `demo-001` broke `latest/download/SHA256SUMS` for about 30 seconds. Use a draft until the release is the real one. | ||
| 87 | + - Tags are immutable: a push cannot delete one, only the repository's Tags page can. | ||
| 88 | + - An asset with an existing name is refused with a 422, and no route to delete an asset was found, so replacing a binary is still open. | ||
| 89 | + - The binaries go through git on the temporary branch: 148 MB per run with all platforms. | ||
| 90 | + | ||
| 91 | + The feature request text is in `demo-rickub-feature-request.txt`. | ||
added
.tickets/issues/0197-how-to-use-mini-me-to-help-making-suggestions-wh.yaml +14 -0 | new file mode 100644 | ||
| @@ -0,0 +1,14 @@ | ||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | |
| 2 | +id: 197 | |
| 3 | +title: How to use mini me to help making suggestions when coding | |
| 4 | +state: open | |
| 5 | +author: | |
| 6 | + name: k33g | |
| 7 | + email: ph.charriere@gmail.com | |
| 8 | +createdAt: 2026-11-07T08:02:50.274Z | |
| 9 | +updatedAt: 2026-11-07T08:02:50.274Z | |
| 10 | +labels: [] | |
| 11 | +milestone: v1.0.6 | |
| 12 | +body: "" | |
| 13 | +tasks: [] | |
| 14 | +comments: [] | |
| new file mode 100644 | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | ||
| 2 | +id: 197 | ||
| 3 | +title: How to use mini me to help making suggestions when coding | ||
| 4 | +state: open | ||
| 5 | +author: | ||
| 6 | + name: k33g | ||
| 7 | + email: ph.charriere@gmail.com | ||
| 8 | +createdAt: 2026-11-07T08:02:50.274Z | ||
| 9 | +updatedAt: 2026-11-07T08:02:50.274Z | ||
| 10 | +labels: [] | ||
| 11 | +milestone: v1.0.6 | ||
| 12 | +body: "" | ||
| 13 | +tasks: [] | ||
| 14 | +comments: [] | ||
added
.tickets/issues/0198-gardening-the-root-of-the-repository.yaml +14 -0 | new file mode 100644 | ||
| @@ -0,0 +1,14 @@ | ||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | |
| 2 | +id: 198 | |
| 3 | +title: Gardening the root of the repository | |
| 4 | +state: open | |
| 5 | +author: | |
| 6 | + name: k33g | |
| 7 | + email: ph.charriere@gmail.com | |
| 8 | +createdAt: 2026-11-07T08:05:54.088Z | |
| 9 | +updatedAt: 2026-11-07T08:05:54.088Z | |
| 10 | +labels: [] | |
| 11 | +milestone: v1.0.5 | |
| 12 | +body: "" | |
| 13 | +tasks: [] | |
| 14 | +comments: [] | |
| new file mode 100644 | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | +# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. | ||
| 2 | +id: 198 | ||
| 3 | +title: Gardening the root of the repository | ||
| 4 | +state: open | ||
| 5 | +author: | ||
| 6 | + name: k33g | ||
| 7 | + email: ph.charriere@gmail.com | ||
| 8 | +createdAt: 2026-11-07T08:05:54.088Z | ||
| 9 | +updatedAt: 2026-11-07T08:05:54.088Z | ||
| 10 | +labels: [] | ||
| 11 | +milestone: v1.0.5 | ||
| 12 | +body: "" | ||
| 13 | +tasks: [] | ||
| 14 | +comments: [] | ||
modified
01-release.tag.sh +5 -6 | @@ -1,10 +1,9 @@ | ||
| 1 | 1 | #!/bin/bash |
| 2 | 2 | : <<'COMMENT' |
| 3 | -1. Update TAG and ABOUT in release.env | |
| 3 | +1. Update TAG and ABOUT in .release.env | |
| 4 | 4 | 2. Run this script: ./01-release.tag.sh (commit, push, tag, push the tag) |
| 5 | -3. Watch the "Release" workflow on Rickub (Actions tab): the tag push starts | |
| 6 | - it; it builds the binaries with ./02-build-releases.sh and publishes the | |
| 7 | - release with them, using the job's own token. No personal token is needed. | |
| 5 | +3. Run the local-ci-*.sh scripts in order: they build on this machine and | |
| 6 | + publish. The tag push no longer starts a workflow (.github.bak). | |
| 8 | 7 | COMMENT |
| 9 | 8 | |
| 10 | 9 | # Without this, a failing step is ignored and the next one runs anyway. That is |
| @@ -14,7 +13,7 @@ COMMENT | ||
| 14 | 13 | set -euo pipefail |
| 15 | 14 | |
| 16 | 15 | set -o allexport |
| 17 | -source release.env | |
| 16 | +source .release.env | |
| 18 | 17 | set +o allexport |
| 19 | 18 | |
| 20 | 19 | echo "Generating release: ${TAG} ${ABOUT}" |
| @@ -42,7 +41,7 @@ tagExists() { | ||
| 42 | 41 | |
| 43 | 42 | if where="$(tagExists)"; then |
| 44 | 43 | echo "❌ ${TAG} already exists ${where}" |
| 45 | - echo "💡 Bump TAG in release.env, or move the tag onto this commit:" | |
| 44 | + echo "💡 Bump TAG in .release.env, or move the tag onto this commit:" | |
| 46 | 45 | echo " git tag -f -a ${TAG} -m \"${ABOUT}\"" |
| 47 | 46 | echo " git push --force origin ${TAG}" |
| 48 | 47 | exit 1 |
| @@ -1,10 +1,9 @@ | |||
| 1 | #!/bin/bash | 1 | #!/bin/bash |
| 2 | : <<'COMMENT' | 2 | : <<'COMMENT' |
| 3 | -1. Update TAG and ABOUT in release.env | 3 | +1. Update TAG and ABOUT in .release.env |
| 4 | 2. Run this script: ./01-release.tag.sh (commit, push, tag, push the tag) | 4 | 2. Run this script: ./01-release.tag.sh (commit, push, tag, push the tag) |
| 5 | -3. Watch the "Release" workflow on Rickub (Actions tab): the tag push starts | 5 | +3. Run the local-ci-*.sh scripts in order: they build on this machine and |
| 6 | - it; it builds the binaries with ./02-build-releases.sh and publishes the | 6 | + publish. The tag push no longer starts a workflow (.github.bak). |
| 7 | - release with them, using the job's own token. No personal token is needed. | ||
| 8 | COMMENT | 7 | COMMENT |
| 9 | 8 | ||
| 10 | # Without this, a failing step is ignored and the next one runs anyway. That is | 9 | # Without this, a failing step is ignored and the next one runs anyway. That is |
| @@ -14,7 +13,7 @@ COMMENT | |||
| 14 | set -euo pipefail | 13 | set -euo pipefail |
| 15 | 14 | ||
| 16 | set -o allexport | 15 | set -o allexport |
| 17 | -source release.env | 16 | +source .release.env |
| 18 | set +o allexport | 17 | set +o allexport |
| 19 | 18 | ||
| 20 | echo "Generating release: ${TAG} ${ABOUT}" | 19 | echo "Generating release: ${TAG} ${ABOUT}" |
| @@ -42,7 +41,7 @@ tagExists() { | |||
| 42 | 41 | ||
| 43 | if where="$(tagExists)"; then | 42 | if where="$(tagExists)"; then |
| 44 | echo "❌ ${TAG} already exists ${where}" | 43 | echo "❌ ${TAG} already exists ${where}" |
| 45 | - echo "💡 Bump TAG in release.env, or move the tag onto this commit:" | 44 | + echo "💡 Bump TAG in .release.env, or move the tag onto this commit:" |
| 46 | echo " git tag -f -a ${TAG} -m \"${ABOUT}\"" | 45 | echo " git tag -f -a ${TAG} -m \"${ABOUT}\"" |
| 47 | echo " git push --force origin ${TAG}" | 46 | echo " git push --force origin ${TAG}" |
| 48 | exit 1 | 47 | exit 1 |
modified
02-build-releases.sh +6 -6 | @@ -3,7 +3,7 @@ | ||
| 3 | 3 | Build the release binaries of mm and stage them under release/${TAG}/ |
| 4 | 4 | |
| 5 | 5 | Usage: |
| 6 | - ./02-build-releases.sh # TAG and ABOUT come from release.env | |
| 6 | + ./02-build-releases.sh # TAG and ABOUT come from .release.env | |
| 7 | 7 | ./02-build-releases.sh v0.2.0 # override the tag for this run (what CI does) |
| 8 | 8 | |
| 9 | 9 | Only the Go toolchain is needed: every binary is a plain `go build`, there is |
| @@ -18,22 +18,22 @@ COMMENT | ||
| 18 | 18 | |
| 19 | 19 | set -euo pipefail |
| 20 | 20 | |
| 21 | -# release.env carries TAG ("v0.2.0") and ABOUT (the one-line description). It | |
| 21 | +# .release.env carries TAG ("v0.2.0") and ABOUT (the one-line description). It | |
| 22 | 22 | # is git-ignored (*.env), so a CI job does not have it: there the tag comes |
| 23 | 23 | # from the command line and ABOUT from the environment, or defaults to the |
| 24 | 24 | # tag. A tag given on the command line always wins, so a test build never |
| 25 | 25 | # edits the file. |
| 26 | -if [ -f release.env ]; then | |
| 27 | - source release.env | |
| 26 | +if [ -f .release.env ]; then | |
| 27 | + source .release.env | |
| 28 | 28 | fi |
| 29 | 29 | TAG="${1:-${TAG:-}}" |
| 30 | 30 | ABOUT="${ABOUT:-Mini Me ${TAG}}" |
| 31 | 31 | |
| 32 | 32 | # A tag that is not vMAJOR.MINOR.PATCH[-prerelease] is a typo — measured: a |
| 33 | -# release.env with "v0.o.0" (letter o) would otherwise build and stage | |
| 33 | +# .release.env with "v0.o.0" (letter o) would otherwise build and stage | |
| 34 | 34 | # binaries nobody can name. |
| 35 | 35 | if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then |
| 36 | - echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env)" | |
| 36 | + echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check .release.env)" | |
| 37 | 37 | exit 1 |
| 38 | 38 | fi |
| 39 | 39 | |
| @@ -3,7 +3,7 @@ | |||
| 3 | Build the release binaries of mm and stage them under release/${TAG}/ | 3 | Build the release binaries of mm and stage them under release/${TAG}/ |
| 4 | 4 | ||
| 5 | Usage: | 5 | Usage: |
| 6 | - ./02-build-releases.sh # TAG and ABOUT come from release.env | 6 | + ./02-build-releases.sh # TAG and ABOUT come from .release.env |
| 7 | ./02-build-releases.sh v0.2.0 # override the tag for this run (what CI does) | 7 | ./02-build-releases.sh v0.2.0 # override the tag for this run (what CI does) |
| 8 | 8 | ||
| 9 | Only the Go toolchain is needed: every binary is a plain `go build`, there is | 9 | Only the Go toolchain is needed: every binary is a plain `go build`, there is |
| @@ -18,22 +18,22 @@ COMMENT | |||
| 18 | 18 | ||
| 19 | set -euo pipefail | 19 | set -euo pipefail |
| 20 | 20 | ||
| 21 | -# release.env carries TAG ("v0.2.0") and ABOUT (the one-line description). It | 21 | +# .release.env carries TAG ("v0.2.0") and ABOUT (the one-line description). It |
| 22 | # is git-ignored (*.env), so a CI job does not have it: there the tag comes | 22 | # is git-ignored (*.env), so a CI job does not have it: there the tag comes |
| 23 | # from the command line and ABOUT from the environment, or defaults to the | 23 | # from the command line and ABOUT from the environment, or defaults to the |
| 24 | # tag. A tag given on the command line always wins, so a test build never | 24 | # tag. A tag given on the command line always wins, so a test build never |
| 25 | # edits the file. | 25 | # edits the file. |
| 26 | -if [ -f release.env ]; then | 26 | +if [ -f .release.env ]; then |
| 27 | - source release.env | 27 | + source .release.env |
| 28 | fi | 28 | fi |
| 29 | TAG="${1:-${TAG:-}}" | 29 | TAG="${1:-${TAG:-}}" |
| 30 | ABOUT="${ABOUT:-Mini Me ${TAG}}" | 30 | ABOUT="${ABOUT:-Mini Me ${TAG}}" |
| 31 | 31 | ||
| 32 | # A tag that is not vMAJOR.MINOR.PATCH[-prerelease] is a typo — measured: a | 32 | # A tag that is not vMAJOR.MINOR.PATCH[-prerelease] is a typo — measured: a |
| 33 | -# release.env with "v0.o.0" (letter o) would otherwise build and stage | 33 | +# .release.env with "v0.o.0" (letter o) would otherwise build and stage |
| 34 | # binaries nobody can name. | 34 | # binaries nobody can name. |
| 35 | if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then | 35 | if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then |
| 36 | - echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env)" | 36 | + echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check .release.env)" |
| 37 | exit 1 | 37 | exit 1 |
| 38 | fi | 38 | fi |
| 39 | 39 | ||
renamed
demos/learning-rust/.gitignore +0 -0 | similarity index 100% | ||
| rename from learning-rust/.gitignore | ||
| rename to demos/learning-rust/.gitignore |
| similarity index 100% | |||
| rename from learning-rust/.gitignore | |||
| rename to demos/learning-rust/.gitignore |
renamed
demos/learning-rust/agent-config/agent.yaml +0 -0 | similarity index 100% | ||
| rename from learning-rust/agent-config/agent.yaml | ||
| rename to demos/learning-rust/agent-config/agent.yaml |
| similarity index 100% | |||
| rename from learning-rust/agent-config/agent.yaml | |||
| rename to demos/learning-rust/agent-config/agent.yaml |
renamed
demos/learning-rust/agent-config/docs/01-getting-started.md +0 -0 | similarity index 100% | ||
| rename from learning-rust/agent-config/docs/01-getting-started.md | ||
| rename to demos/learning-rust/agent-config/docs/01-getting-started.md |
| similarity index 100% | |||
| rename from learning-rust/agent-config/docs/01-getting-started.md | |||
| rename to demos/learning-rust/agent-config/docs/01-getting-started.md |
renamed
demos/learning-rust/agent-config/docs/02-layout.md +0 -0 | similarity index 100% | ||
| rename from learning-rust/agent-config/docs/02-layout.md | ||
| rename to demos/learning-rust/agent-config/docs/02-layout.md |
| similarity index 100% | |||
| rename from learning-rust/agent-config/docs/02-layout.md | |||
| rename to demos/learning-rust/agent-config/docs/02-layout.md |
renamed
demos/learning-rust/agent-config/docs/03-blocks-and-paragraphs.md +0 -0 | similarity index 100% | ||
| rename from learning-rust/agent-config/docs/03-blocks-and-paragraphs.md | ||
| rename to demos/learning-rust/agent-config/docs/03-blocks-and-paragraphs.md |
| similarity index 100% | |||
| rename from learning-rust/agent-config/docs/03-blocks-and-paragraphs.md | |||
| rename to demos/learning-rust/agent-config/docs/03-blocks-and-paragraphs.md |
renamed
demos/learning-rust/agent-config/docs/04-lists.md +0 -0 | similarity index 100% | ||
| rename from learning-rust/agent-config/docs/04-lists.md | ||
| rename to demos/learning-rust/agent-config/docs/04-lists.md |
| similarity index 100% | |||
| rename from learning-rust/agent-config/docs/04-lists.md | |||
| rename to demos/learning-rust/agent-config/docs/04-lists.md |
renamed
demos/learning-rust/agent-config/docs/05-tables.md +0 -0 | similarity index 100% | ||
| rename from learning-rust/agent-config/docs/05-tables.md | ||
| rename to demos/learning-rust/agent-config/docs/05-tables.md |
| similarity index 100% | |||
| rename from learning-rust/agent-config/docs/05-tables.md | |||
| rename to demos/learning-rust/agent-config/docs/05-tables.md |
renamed
demos/learning-rust/agent-config/docs/06-gauges-and-ticks.md +0 -0 | similarity index 100% | ||
| rename from learning-rust/agent-config/docs/06-gauges-and-ticks.md | ||
| rename to demos/learning-rust/agent-config/docs/06-gauges-and-ticks.md |
| similarity index 100% | |||
| rename from learning-rust/agent-config/docs/06-gauges-and-ticks.md | |||
| rename to demos/learning-rust/agent-config/docs/06-gauges-and-ticks.md |
renamed
demos/learning-rust/agent-config/docs/07-tabs.md +0 -0 | similarity index 100% | ||
| rename from learning-rust/agent-config/docs/07-tabs.md | ||
| rename to demos/learning-rust/agent-config/docs/07-tabs.md |
| similarity index 100% | |||
| rename from learning-rust/agent-config/docs/07-tabs.md | |||
| rename to demos/learning-rust/agent-config/docs/07-tabs.md |
renamed
demos/learning-rust/agent-config/docs/08-app-state-and-events.md +0 -0 | similarity index 100% | ||
| rename from learning-rust/agent-config/docs/08-app-state-and-events.md | ||
| rename to demos/learning-rust/agent-config/docs/08-app-state-and-events.md |
| similarity index 100% | |||
| rename from learning-rust/agent-config/docs/08-app-state-and-events.md | |||
| rename to demos/learning-rust/agent-config/docs/08-app-state-and-events.md |
renamed
demos/learning-rust/agent-config/docs/09-popups.md +0 -0 | similarity index 100% | ||
| rename from learning-rust/agent-config/docs/09-popups.md | ||
| rename to demos/learning-rust/agent-config/docs/09-popups.md |
| similarity index 100% | |||
| rename from learning-rust/agent-config/docs/09-popups.md | |||
| rename to demos/learning-rust/agent-config/docs/09-popups.md |
renamed
demos/learning-rust/agent-config/docs/README.md +0 -0 | similarity index 100% | ||
| rename from learning-rust/agent-config/docs/README.md | ||
| rename to demos/learning-rust/agent-config/docs/README.md |
| similarity index 100% | |||
| rename from learning-rust/agent-config/docs/README.md | |||
| rename to demos/learning-rust/agent-config/docs/README.md |
renamed
demos/learning-rust/sbxenv.yaml +0 -0 | similarity index 100% | ||
| rename from learning-rust/sbxenv.yaml | ||
| rename to demos/learning-rust/sbxenv.yaml |
| similarity index 100% | |||
| rename from learning-rust/sbxenv.yaml | |||
| rename to demos/learning-rust/sbxenv.yaml |
renamed
demos/learning-rust/start-zed.sh +0 -0 | similarity index 100% | ||
| rename from learning-rust/start-zed.sh | ||
| rename to demos/learning-rust/start-zed.sh |
| similarity index 100% | |||
| rename from learning-rust/start-zed.sh | |||
| rename to demos/learning-rust/start-zed.sh |
renamed
demos/learning-rust/stop-zed.sh +0 -0 | similarity index 100% | ||
| rename from learning-rust/stop-zed.sh | ||
| rename to demos/learning-rust/stop-zed.sh |
| similarity index 100% | |||
| rename from learning-rust/stop-zed.sh | |||
| rename to demos/learning-rust/stop-zed.sh |
renamed
demos/learning-rust/workspace/.gitkeep +0 -0 | similarity index 100% | ||
| rename from learning-rust/workspace/.gitkeep | ||
| rename to demos/learning-rust/workspace/.gitkeep |
| similarity index 100% | |||
| rename from learning-rust/workspace/.gitkeep | |||
| rename to demos/learning-rust/workspace/.gitkeep |
deleted
guides/agent-settings-for-small-models.md +0 -217 | deleted file mode 100644 | ||
| @@ -1,217 +0,0 @@ | ||
| 1 | -# Agent settings for small models (in plain words) | |
| 2 | - | |
| 3 | -*[Version française](reglages-agents-petits-modeles.md)* | |
| 4 | - | |
| 5 | -> This guide explains, without jargon, what each setting of a mini-me agent does, why it exists, what its default value is, and how to set it **when you run a small language model locally** (one that fits on your laptop, not a giant model in the cloud). | |
| 6 | - | |
| 7 | -## Why these settings exist | |
| 8 | - | |
| 9 | -A small local model (a few billion parameters, running on a consumer CPU/GPU) does not have the same weaknesses as a large cloud model: | |
| 10 | - | |
| 11 | -- it is **slow**, above all when it reads a long prompt ("prompt processing"); | |
| 12 | -- it has a **limited memory (context window)**, often 8k to 32k tokens, sometimes less; | |
| 13 | -- it **loops or drifts** more easily (repeats the same command, forgets what it already read, spins off in its reasoning); | |
| 14 | -- it can **hallucinate** the result of a command it never actually ran. | |
| 15 | - | |
| 16 | -The settings below are the safeguards that make up for this. They tell the agent "stop if you are too slow", "do not keep everything in memory", "do not go round in circles forever", "do not send back a wall of text that clogs your own memory". | |
| 17 | - | |
| 18 | -They go in the agent's YAML file (`agent.*.yaml`), under the same key names. | |
| 19 | - | |
| 20 | ---- | |
| 21 | - | |
| 22 | -## 1. `contextWindow`: the size of the model's memory | |
| 23 | - | |
| 24 | -**In plain words**: the size of the model's "working memory", in tokens (one token ≈ 0.75 word). Everything the agent said, read and ran must fit in it. When it is full, room must be made (see the `context` section below). | |
| 25 | - | |
| 26 | -- **Default value**: `0`, meaning "I don't know, ask the server". If the server (llama.cpp, Docker Model Runner…) reports the context size it was configured with, mini-me uses it automatically. | |
| 27 | -- **How to set it**: usually, **do not set it yourself** when your server can report it: leave `0`. Set it by hand only when your server does not report it, and then use the real value you configured on the server (e.g. `-c 8192` on `llama-server` → `contextWindow: 8192`). | |
| 28 | -- **For a small model**: small models often come with an advertised window of 32k or more, but **in practice their quality drops well before** that limit. Knowing the real usable value keeps the context-compression calculations (section 8) reliable. | |
| 29 | - | |
| 30 | ---- | |
| 31 | - | |
| 32 | -## 2. `firstTokenTimeout`: how long the model may take to *start* answering | |
| 33 | - | |
| 34 | -**In plain words**: before the model produces its first word, the server must *read* the whole prompt (the question + the history + the instructions). On a small local model, reading a 20-30k-token prompt can take several minutes. This setting says: "how long do I wait before deciding that it crashed?" | |
| 35 | - | |
| 36 | -- **Default value**: `3 minutes`. | |
| 37 | -- **Special feature**: when the server (llama.cpp) reports its reading progress meanwhile, the clock **restarts** at each report. So in practice it will not cut as long as the server is making progress: this timeout mostly protects against a real, silent hang. | |
| 38 | -- **How to set it**: | |
| 39 | - - Small model (≤ 8B) with a good GPU: the default (3 min) is usually enough. | |
| 40 | - - Larger model (15-30B), modest machine (CPU only, little VRAM), or very long prompts (big `AGENTS.md`, long history): raise it to `5m` or even `10m`. | |
| 41 | - - Golden rule: **never shorter than `watchdogTimeout`** (see just below), or the protection makes no sense. | |
| 42 | - | |
| 43 | ---- | |
| 44 | - | |
| 45 | -## 3. `watchdogTimeout`: the watchdog while the model *generates* | |
| 46 | - | |
| 47 | -**In plain words**: once the model has started answering (or using a tool), this setting checks that it keeps producing something regularly. If it stays silent longer than this, *with nothing new coming out*, mini-me decides the connection is stuck and cuts it. | |
| 48 | - | |
| 49 | -- **Default value**: `20 seconds`. | |
| 50 | -- **Difference from `firstTokenTimeout`**: `firstTokenTimeout` watches the **start** (reading the prompt), `watchdogTimeout` watches **what follows** (token-by-token generation, or a tool running). That is why `watchdogTimeout` is much shorter. | |
| 51 | -- **How to set it**: | |
| 52 | - - If the agent has the `bash` tool and commands may legitimately take time (build, tests, downloads), **raise this timeout together with `bashTimeout`**: while a bash command runs, the watchdog keeps counting. If `bashTimeout` is `2m`, `watchdogTimeout` must be at least `2m` too, or mini-me would cut the command before it ends. | |
| 53 | - - For a simple "chat" use without heavy tools: the default is fine, even on a slow small model (token-by-token generation is what counts, not overall speed). | |
| 54 | - | |
| 55 | ---- | |
| 56 | - | |
| 57 | -## 4. `bashTimeout`: how long a shell command may run | |
| 58 | - | |
| 59 | -**In plain words**: when the agent runs a command (`bash`), this is the longest it may run before mini-me kills it, even if it has printed nothing. | |
| 60 | - | |
| 61 | -- **Default value**: `30 seconds`. | |
| 62 | -- **How to set it**: | |
| 63 | - - Quick tasks (reading a file, `git status`, `ls`): the 30 s default is plenty. | |
| 64 | - - Heavy tasks you expect (compiling, tests, installing dependencies, a long search): raise it generously, for example `2m`, `5m`, or more depending on the project. | |
| 65 | - - **Always raise `watchdogTimeout` at the same time** (see section 3). It is the most common trap: a command is killed by the watchdog although `bashTimeout` gave it time. | |
| 66 | - - This setting depends less on the size of the model than on the kind of project the agent works on. | |
| 67 | - | |
| 68 | ---- | |
| 69 | - | |
| 70 | -## 5. `maxTurns`: how many model ↔ tool round trips one question may take | |
| 71 | - | |
| 72 | -**In plain words**: to answer one question, the agent may go round several times: "I run a command" → "I look at the result" → "I run another one" → and so on. This setting caps the number of rounds before mini-me stops the agent (so that it cannot loop forever). | |
| 73 | - | |
| 74 | -- **Default value**: `10`. | |
| 75 | -- **Value actually used in the shipped configurations**: `40`. Experience shows that 10 is often too low for realistic coding tasks with a small model, which needs more iterations (re-reading, fixing, trying again) than a large one. | |
| 76 | -- **How to set it**: | |
| 77 | - - Narrow task, a single action expected (a factual question, one tool call): `8` to `15` is enough, and it protects better against loops. | |
| 78 | - - General coding agent (exploring code, editing, testing): `40` to `60` is reasonable, especially with a small model that needs several tries. | |
| 79 | - - The smaller or weaker the model, the more likely it is to loop without ever concluding: pair a generous `maxTurns` with good loop detection rather than setting a huge value "just in case". | |
| 80 | - | |
| 81 | ---- | |
| 82 | - | |
| 83 | -## 6. `maxOutput`: the most a tool may send back to the model | |
| 84 | - | |
| 85 | -**In plain words**: if a `bash` command returns 500,000 characters (a big log file, for example), we do not want it to fill the model's whole memory at once. This setting truncates the result before the model sees it. | |
| 86 | - | |
| 87 | -- **Default value**: `16000` characters. | |
| 88 | -- **How it truncates**: not just by cutting the end. mini-me keeps the **beginning** of the output and up to 2000 characters of the **end**, because the useful information (an error, a summary) is often at the end of a long output. | |
| 89 | -- **How to set it**: | |
| 90 | - - Small model with a small context window (8k-16k tokens): **lower** it, for example to `4000`-`8000`, so that one command cannot use up a third of the available memory. | |
| 91 | - - Model with a large context window, or an agent that really needs to see whole outputs (e.g. analysing a big diff): you can raise it to `20000`-`30000`, but remember that every output "costs" tokens and brings forward the moment the context compression (section 8) kicks in. | |
| 92 | - | |
| 93 | ---- | |
| 94 | - | |
| 95 | -## 7. `agentsMd`: how the agent reads its project instructions | |
| 96 | - | |
| 97 | -**In plain words**: `AGENTS.md` (or an equivalent file) holds the project's own instructions, which the agent must follow. This block controls whether and how that file is loaded. | |
| 98 | - | |
| 99 | -```yaml | |
| 100 | -agentsMd: | |
| 101 | - enabled: true | |
| 102 | - path: "AGENTS.md" | |
| 103 | - maxChars: 0 | |
| 104 | -``` | |
| 105 | - | |
| 106 | -- **`enabled`**, default `true`: reads the file automatically. | |
| 107 | -- **`path`**, default `"AGENTS.md"`: the name or path of the file to read. | |
| 108 | -- **`maxChars`**, default `0` (= no limit). | |
| 109 | - | |
| 110 | -### The important point about `maxChars` | |
| 111 | - | |
| 112 | -It is **not** a truncation. When `AGENTS.md` is longer than `maxChars` characters, it is **not cut**: it is **left out entirely** (the source code says why: cutting in the middle could drop the very rule that matters). The start-up banner says so (`skipped (too long)`) rather than pretending the whole file was read. | |
| 113 | - | |
| 114 | -- **How to set it**: | |
| 115 | - - **Even without `maxChars`, mini-me warns you**: the start-up banner warns when `AGENTS.md` takes **20 % or more** of a known context window (estimate: number of characters ÷ 3.5). With a small model, that is the sign to shorten the file. | |
| 116 | - - **`maxChars` is a hard limit on top of that warning.** With a small model and a small window, a long `AGENTS.md` can take a large share of the memory before the conversation even starts. Setting `maxChars` guarantees it never goes beyond: above it, the file is left out, the banner says so, and you know it must be shortened. | |
| 117 | - - To compute a value: 20 % of the window × 3.5. Example: an 8192-token window → 20 % = 1638 tokens → about `maxChars: 5700`. | |
| 118 | - - If your `AGENTS.md` is short (a few hundred lines at most) and your model has a comfortable window (32k+), you can leave `0`. | |
| 119 | - | |
| 120 | ---- | |
| 121 | - | |
| 122 | -## 8. `context`: automatic compression of the history | |
| 123 | - | |
| 124 | -**In plain words**: as the conversation goes on, the history (questions, answers, command results) grows. On a small model with limited memory, there comes a point where it no longer fits. This block decides **when** and **how** the older exchanges are summarised automatically to make room, without losing the thread. | |
| 125 | - | |
| 126 | -```yaml | |
| 127 | -context: | |
| 128 | - enabled: false | |
| 129 | - threshold: 75 | |
| 130 | - maxMessages: 80 | |
| 131 | - keepLastTurns: 3 | |
| 132 | - summaryMaxTokens: 1200 | |
| 133 | - prompt: "" | |
| 134 | - showStats: true | |
| 135 | -``` | |
| 136 | - | |
| 137 | -| Sub-setting | Default | What it does | How to set it | | |
| 138 | -|---|---|---|---| | |
| 139 | -| `enabled` | `false` | Turns automatic compression on. Even when it is off, you can still compress by hand (`/compact`). | **Turn it on (`true`) for any small local model**: it is the main protection against a "full context" that makes the agent fail or degrade. | | |
| 140 | -| `threshold` | `75` (%) | Share of the context window beyond which compression starts. 75 % deliberately leaves a quarter of the memory free for the next question, the tool results and the answer. | Not too low (you would compress too often and lose continuity); not too high (you risk filling up before compression can act). 70-80 % is a good range. | | |
| 141 | -| `maxMessages` | `80` | Fallback trigger based on the *number* of messages, used when the window size is unknown (`contextWindow: 0` and a server that does not say). One command = 2 messages (the call + the result), so 80 ≈ 30 commands of history. | The code justifies 80 as roughly the point where a 12B local model starts to slow down. On a smaller model, you can lower it if the agent gets slower or confused before 80 messages. Set `0` to turn this trigger off when you are sure of `contextWindow`. | | |
| 142 | -| `keepLastTurns` | `3` | Number of most recent turns kept **as they are** (not summarised): that is where the agent is actively working, and summarising it would make the agent redo what it has just done. | Keep at least `2`-`3`. Raise it a little (`4`-`5`) if the agent "forgets" a very recent action right after a compression. | | |
| 143 | -| `summaryMaxTokens` | `1200` | Largest summary generated to replace the old exchanges. The cap stops a runaway model from writing a summary that itself fills the window it was meant to empty. | For a small model, do not raise it much: a summary must stay compact. `1200` suits most cases; go down to `600`-`800` to save even more room. | | |
| 144 | -| `prompt` | `""` (built-in prompt) | Replaces the prompt used to ask for the summary. | Leave it empty unless you have a specific need (e.g. a summary that keeps a particular format). | | |
| 145 | -| `showStats` | `true` | Prints an information line after each compression (how many tokens were saved, etc.). | Leave it on: it shows that compression does its job. Turn it off only for a quieter output. | | |
| 146 | - | |
| 147 | -**Practical tip**: the summary is requested **without the tools and without "reasoning" mode**, precisely so that `summaryMaxTokens` is not wasted on thinking instead of a useful summary. | |
| 148 | - | |
| 149 | ---- | |
| 150 | - | |
| 151 | -## Summary: typical profiles | |
| 152 | - | |
| 153 | -| Situation | `firstTokenTimeout` | `watchdogTimeout` | `bashTimeout` | `maxTurns` | `maxOutput` | `context.enabled` | | |
| 154 | -|---|---|---|---|---|---|---| | |
| 155 | -| Small model (≤ 8B), short tasks/chat, no `bash` or commands under 20 s | `3m` (default) | `20s` (default) | `30s` (default) | `15` | `8000` | `true` | | |
| 156 | -| Small/medium model, general coding agent | `5m` | `2m` (aligned on bashTimeout) | `2m` | `40` | `16000` | `true` | | |
| 157 | -| Larger model or modest machine (CPU) | `10m` | `5m` | `5m` | `40`-`60` | `16000`-`24000` | `true` | | |
| 158 | - | |
| 159 | -In the first row, `watchdogTimeout` (20 s) is shorter than `bashTimeout` (30 s): those are the defaults, and they only fit when no command runs longer than 20 s. As soon as the agent runs longer commands, align the two as in the other rows (section 3). | |
| 160 | - | |
| 161 | -These profiles are starting points, not absolute truths: adjust them by watching how your model actually behaves (does it loop, is it cut too early, does the context fill up too fast). | |
| 162 | - | |
| 163 | ---- | |
| 164 | - | |
| 165 | -## 9. Sampling: how the model picks its words | |
| 166 | - | |
| 167 | -**In plain words**: "sampling" is the set of settings that control how the model picks the next word among all the ones it finds plausible. It decides whether the model is **precise and predictable** or **creative and varied**. Unlike the settings above (timeouts, quotas), sampling has no fixed structure in mini-me: it is a free list of keys (`sampling:` in the YAML) passed almost as is to the model's server. | |
| 168 | - | |
| 169 | -```yaml | |
| 170 | -sampling: | |
| 171 | - temperature: 0.0 | |
| 172 | - top_p: 0.9 | |
| 173 | - max_tokens: 4096 | |
| 174 | -``` | |
| 175 | - | |
| 176 | -These are the only three keys mini-me sets by default. The others (`top_k`, `min_p`, `repeat_penalty`…) have no default: add them yourself if your server and model support them and you need them. | |
| 177 | - | |
| 178 | -### `temperature`: the "precise ↔ creative" dial | |
| 179 | - | |
| 180 | -**In plain words**: the closer it is to `0`, the more the model always picks the word it finds most likely (stable, reproducible answers, sometimes a little rigid). The higher it goes towards `1` (or beyond), the more it accepts less obvious words (more varied answers, but also more risk of mistakes and drift). | |
| 181 | - | |
| 182 | -- **mini-me default**: `0.0`, deliberately very low, because mini-me is designed as a **coding agent**, where precision and reproducibility matter, not creativity. | |
| 183 | -- **How to set it for a small model**: | |
| 184 | - - An agent that runs commands, writes code, follows strict instructions: **keep `0.0`-`0.2`**. A small model already makes more mistakes and loops more than a large one; a low temperature reduces that risk. | |
| 185 | - - A conversational or creative agent, or one that must rephrase or brainstorm: go up to `0.5`-`0.8`. Beyond `0.8`, a small model more easily turns incoherent. | |
| 186 | - | |
| 187 | -### `top_p` (nucleus sampling): how wide the choice is | |
| 188 | - | |
| 189 | -**In plain words**: instead of considering every possible word, the model only looks at the smallest group of words whose combined probability reaches this share. `top_p: 0.9` means "only consider the words that together cover 90 % of the probability; ignore the long tail of unlikely ones". | |
| 190 | - | |
| 191 | -- **mini-me default**: `0.9`. | |
| 192 | -- **How to set it**: together with a low `temperature`, `0.9` is already a good "safe" compromise for a small model. You can go down to `0.8` to cut odd detours further; there is no point going higher for a coding agent. | |
| 193 | - | |
| 194 | -### `top_k`: limiting the number of candidates (optional, no default in mini-me) | |
| 195 | - | |
| 196 | -**In plain words**: keep only the `k` most likely words at each step and ignore the rest, whatever `top_p` says. | |
| 197 | - | |
| 198 | -- **How to set it**: small models (often small Qwen, Gemma or Llama) do not all react to `top_k` the same way, and some model families explicitly recommend a value (for example `20`-`40`) in their model card. **Check the metadata or recommendations of the GGUF model you use** rather than guessing: a poorly chosen `top_k` can make a small model more repetitive or, on the contrary, more unstable. | |
| 199 | - | |
| 200 | -### `repeat_penalty` / `min_p`: against repetition (optional, no default in mini-me) | |
| 201 | - | |
| 202 | -**In plain words**: `repeat_penalty` penalises the model for reusing a word it used recently (useful against repetition loops, a classic weakness of small models). `min_p` is an alternative to `top_p` that drops the words whose probability is too low compared with the most likely word at that moment. | |
| 203 | - | |
| 204 | -- **How to set them**: these are typically the settings that **vary most from one model family to another**; there is no universal value. Good practice is to use the values the model card recommends (often in the GGUF metadata or the model's documentation) rather than improvising. If the agent repeats sentences or actions in a loop, this is often the first setting to adjust, together with mini-me's loop detector and `maxTurns` (section 5). | |
| 205 | - | |
| 206 | -### `max_tokens`: the longest an answer may be | |
| 207 | - | |
| 208 | -**In plain words**: how many tokens the model may generate in one answer before it is cut. | |
| 209 | - | |
| 210 | -- **mini-me default**: `4096`. | |
| 211 | -- **How to set it**: for a small model with a small context window, check that `max_tokens` leaves enough room in the window for the prompt itself: `max_tokens` + prompt size must not exceed `contextWindow`. Lower it (`1024`-`2048`) if your answers must stay short (e.g. classification, extraction); keep the default for an agent that writes code or longer explanations. | |
| 212 | - | |
| 213 | -### In short: mini-me's sampling philosophy | |
| 214 | - | |
| 215 | -mini-me assumes that a **small local model is a coding agent first**, so its default sampling favours **precision and reproducibility** (`temperature: 0.0`) over creativity. It is the safest starting point to limit mistakes, hallucinated command results and loops; loosen it yourself if your use is more conversational or creative. | |
| 216 | - | |
| 217 | -> mini-me has no automatic "sampling profile" per model family today: the defaults are generic and deliberately conservative. When you switch models, check these settings again rather than keeping another model's out of habit. | |
| deleted file mode 100644 | |||
| @@ -1,217 +0,0 @@ | |||
| 1 | -# Agent settings for small models (in plain words) | ||
| 2 | - | ||
| 3 | -*[Version française](reglages-agents-petits-modeles.md)* | ||
| 4 | - | ||
| 5 | -> This guide explains, without jargon, what each setting of a mini-me agent does, why it exists, what its default value is, and how to set it **when you run a small language model locally** (one that fits on your laptop, not a giant model in the cloud). | ||
| 6 | - | ||
| 7 | -## Why these settings exist | ||
| 8 | - | ||
| 9 | -A small local model (a few billion parameters, running on a consumer CPU/GPU) does not have the same weaknesses as a large cloud model: | ||
| 10 | - | ||
| 11 | -- it is **slow**, above all when it reads a long prompt ("prompt processing"); | ||
| 12 | -- it has a **limited memory (context window)**, often 8k to 32k tokens, sometimes less; | ||
| 13 | -- it **loops or drifts** more easily (repeats the same command, forgets what it already read, spins off in its reasoning); | ||
| 14 | -- it can **hallucinate** the result of a command it never actually ran. | ||
| 15 | - | ||
| 16 | -The settings below are the safeguards that make up for this. They tell the agent "stop if you are too slow", "do not keep everything in memory", "do not go round in circles forever", "do not send back a wall of text that clogs your own memory". | ||
| 17 | - | ||
| 18 | -They go in the agent's YAML file (`agent.*.yaml`), under the same key names. | ||
| 19 | - | ||
| 20 | ---- | ||
| 21 | - | ||
| 22 | -## 1. `contextWindow`: the size of the model's memory | ||
| 23 | - | ||
| 24 | -**In plain words**: the size of the model's "working memory", in tokens (one token ≈ 0.75 word). Everything the agent said, read and ran must fit in it. When it is full, room must be made (see the `context` section below). | ||
| 25 | - | ||
| 26 | -- **Default value**: `0`, meaning "I don't know, ask the server". If the server (llama.cpp, Docker Model Runner…) reports the context size it was configured with, mini-me uses it automatically. | ||
| 27 | -- **How to set it**: usually, **do not set it yourself** when your server can report it: leave `0`. Set it by hand only when your server does not report it, and then use the real value you configured on the server (e.g. `-c 8192` on `llama-server` → `contextWindow: 8192`). | ||
| 28 | -- **For a small model**: small models often come with an advertised window of 32k or more, but **in practice their quality drops well before** that limit. Knowing the real usable value keeps the context-compression calculations (section 8) reliable. | ||
| 29 | - | ||
| 30 | ---- | ||
| 31 | - | ||
| 32 | -## 2. `firstTokenTimeout`: how long the model may take to *start* answering | ||
| 33 | - | ||
| 34 | -**In plain words**: before the model produces its first word, the server must *read* the whole prompt (the question + the history + the instructions). On a small local model, reading a 20-30k-token prompt can take several minutes. This setting says: "how long do I wait before deciding that it crashed?" | ||
| 35 | - | ||
| 36 | -- **Default value**: `3 minutes`. | ||
| 37 | -- **Special feature**: when the server (llama.cpp) reports its reading progress meanwhile, the clock **restarts** at each report. So in practice it will not cut as long as the server is making progress: this timeout mostly protects against a real, silent hang. | ||
| 38 | -- **How to set it**: | ||
| 39 | - - Small model (≤ 8B) with a good GPU: the default (3 min) is usually enough. | ||
| 40 | - - Larger model (15-30B), modest machine (CPU only, little VRAM), or very long prompts (big `AGENTS.md`, long history): raise it to `5m` or even `10m`. | ||
| 41 | - - Golden rule: **never shorter than `watchdogTimeout`** (see just below), or the protection makes no sense. | ||
| 42 | - | ||
| 43 | ---- | ||
| 44 | - | ||
| 45 | -## 3. `watchdogTimeout`: the watchdog while the model *generates* | ||
| 46 | - | ||
| 47 | -**In plain words**: once the model has started answering (or using a tool), this setting checks that it keeps producing something regularly. If it stays silent longer than this, *with nothing new coming out*, mini-me decides the connection is stuck and cuts it. | ||
| 48 | - | ||
| 49 | -- **Default value**: `20 seconds`. | ||
| 50 | -- **Difference from `firstTokenTimeout`**: `firstTokenTimeout` watches the **start** (reading the prompt), `watchdogTimeout` watches **what follows** (token-by-token generation, or a tool running). That is why `watchdogTimeout` is much shorter. | ||
| 51 | -- **How to set it**: | ||
| 52 | - - If the agent has the `bash` tool and commands may legitimately take time (build, tests, downloads), **raise this timeout together with `bashTimeout`**: while a bash command runs, the watchdog keeps counting. If `bashTimeout` is `2m`, `watchdogTimeout` must be at least `2m` too, or mini-me would cut the command before it ends. | ||
| 53 | - - For a simple "chat" use without heavy tools: the default is fine, even on a slow small model (token-by-token generation is what counts, not overall speed). | ||
| 54 | - | ||
| 55 | ---- | ||
| 56 | - | ||
| 57 | -## 4. `bashTimeout`: how long a shell command may run | ||
| 58 | - | ||
| 59 | -**In plain words**: when the agent runs a command (`bash`), this is the longest it may run before mini-me kills it, even if it has printed nothing. | ||
| 60 | - | ||
| 61 | -- **Default value**: `30 seconds`. | ||
| 62 | -- **How to set it**: | ||
| 63 | - - Quick tasks (reading a file, `git status`, `ls`): the 30 s default is plenty. | ||
| 64 | - - Heavy tasks you expect (compiling, tests, installing dependencies, a long search): raise it generously, for example `2m`, `5m`, or more depending on the project. | ||
| 65 | - - **Always raise `watchdogTimeout` at the same time** (see section 3). It is the most common trap: a command is killed by the watchdog although `bashTimeout` gave it time. | ||
| 66 | - - This setting depends less on the size of the model than on the kind of project the agent works on. | ||
| 67 | - | ||
| 68 | ---- | ||
| 69 | - | ||
| 70 | -## 5. `maxTurns`: how many model ↔ tool round trips one question may take | ||
| 71 | - | ||
| 72 | -**In plain words**: to answer one question, the agent may go round several times: "I run a command" → "I look at the result" → "I run another one" → and so on. This setting caps the number of rounds before mini-me stops the agent (so that it cannot loop forever). | ||
| 73 | - | ||
| 74 | -- **Default value**: `10`. | ||
| 75 | -- **Value actually used in the shipped configurations**: `40`. Experience shows that 10 is often too low for realistic coding tasks with a small model, which needs more iterations (re-reading, fixing, trying again) than a large one. | ||
| 76 | -- **How to set it**: | ||
| 77 | - - Narrow task, a single action expected (a factual question, one tool call): `8` to `15` is enough, and it protects better against loops. | ||
| 78 | - - General coding agent (exploring code, editing, testing): `40` to `60` is reasonable, especially with a small model that needs several tries. | ||
| 79 | - - The smaller or weaker the model, the more likely it is to loop without ever concluding: pair a generous `maxTurns` with good loop detection rather than setting a huge value "just in case". | ||
| 80 | - | ||
| 81 | ---- | ||
| 82 | - | ||
| 83 | -## 6. `maxOutput`: the most a tool may send back to the model | ||
| 84 | - | ||
| 85 | -**In plain words**: if a `bash` command returns 500,000 characters (a big log file, for example), we do not want it to fill the model's whole memory at once. This setting truncates the result before the model sees it. | ||
| 86 | - | ||
| 87 | -- **Default value**: `16000` characters. | ||
| 88 | -- **How it truncates**: not just by cutting the end. mini-me keeps the **beginning** of the output and up to 2000 characters of the **end**, because the useful information (an error, a summary) is often at the end of a long output. | ||
| 89 | -- **How to set it**: | ||
| 90 | - - Small model with a small context window (8k-16k tokens): **lower** it, for example to `4000`-`8000`, so that one command cannot use up a third of the available memory. | ||
| 91 | - - Model with a large context window, or an agent that really needs to see whole outputs (e.g. analysing a big diff): you can raise it to `20000`-`30000`, but remember that every output "costs" tokens and brings forward the moment the context compression (section 8) kicks in. | ||
| 92 | - | ||
| 93 | ---- | ||
| 94 | - | ||
| 95 | -## 7. `agentsMd`: how the agent reads its project instructions | ||
| 96 | - | ||
| 97 | -**In plain words**: `AGENTS.md` (or an equivalent file) holds the project's own instructions, which the agent must follow. This block controls whether and how that file is loaded. | ||
| 98 | - | ||
| 99 | -```yaml | ||
| 100 | -agentsMd: | ||
| 101 | - enabled: true | ||
| 102 | - path: "AGENTS.md" | ||
| 103 | - maxChars: 0 | ||
| 104 | -``` | ||
| 105 | - | ||
| 106 | -- **`enabled`**, default `true`: reads the file automatically. | ||
| 107 | -- **`path`**, default `"AGENTS.md"`: the name or path of the file to read. | ||
| 108 | -- **`maxChars`**, default `0` (= no limit). | ||
| 109 | - | ||
| 110 | -### The important point about `maxChars` | ||
| 111 | - | ||
| 112 | -It is **not** a truncation. When `AGENTS.md` is longer than `maxChars` characters, it is **not cut**: it is **left out entirely** (the source code says why: cutting in the middle could drop the very rule that matters). The start-up banner says so (`skipped (too long)`) rather than pretending the whole file was read. | ||
| 113 | - | ||
| 114 | -- **How to set it**: | ||
| 115 | - - **Even without `maxChars`, mini-me warns you**: the start-up banner warns when `AGENTS.md` takes **20 % or more** of a known context window (estimate: number of characters ÷ 3.5). With a small model, that is the sign to shorten the file. | ||
| 116 | - - **`maxChars` is a hard limit on top of that warning.** With a small model and a small window, a long `AGENTS.md` can take a large share of the memory before the conversation even starts. Setting `maxChars` guarantees it never goes beyond: above it, the file is left out, the banner says so, and you know it must be shortened. | ||
| 117 | - - To compute a value: 20 % of the window × 3.5. Example: an 8192-token window → 20 % = 1638 tokens → about `maxChars: 5700`. | ||
| 118 | - - If your `AGENTS.md` is short (a few hundred lines at most) and your model has a comfortable window (32k+), you can leave `0`. | ||
| 119 | - | ||
| 120 | ---- | ||
| 121 | - | ||
| 122 | -## 8. `context`: automatic compression of the history | ||
| 123 | - | ||
| 124 | -**In plain words**: as the conversation goes on, the history (questions, answers, command results) grows. On a small model with limited memory, there comes a point where it no longer fits. This block decides **when** and **how** the older exchanges are summarised automatically to make room, without losing the thread. | ||
| 125 | - | ||
| 126 | -```yaml | ||
| 127 | -context: | ||
| 128 | - enabled: false | ||
| 129 | - threshold: 75 | ||
| 130 | - maxMessages: 80 | ||
| 131 | - keepLastTurns: 3 | ||
| 132 | - summaryMaxTokens: 1200 | ||
| 133 | - prompt: "" | ||
| 134 | - showStats: true | ||
| 135 | -``` | ||
| 136 | - | ||
| 137 | -| Sub-setting | Default | What it does | How to set it | | ||
| 138 | -|---|---|---|---| | ||
| 139 | -| `enabled` | `false` | Turns automatic compression on. Even when it is off, you can still compress by hand (`/compact`). | **Turn it on (`true`) for any small local model**: it is the main protection against a "full context" that makes the agent fail or degrade. | | ||
| 140 | -| `threshold` | `75` (%) | Share of the context window beyond which compression starts. 75 % deliberately leaves a quarter of the memory free for the next question, the tool results and the answer. | Not too low (you would compress too often and lose continuity); not too high (you risk filling up before compression can act). 70-80 % is a good range. | | ||
| 141 | -| `maxMessages` | `80` | Fallback trigger based on the *number* of messages, used when the window size is unknown (`contextWindow: 0` and a server that does not say). One command = 2 messages (the call + the result), so 80 ≈ 30 commands of history. | The code justifies 80 as roughly the point where a 12B local model starts to slow down. On a smaller model, you can lower it if the agent gets slower or confused before 80 messages. Set `0` to turn this trigger off when you are sure of `contextWindow`. | | ||
| 142 | -| `keepLastTurns` | `3` | Number of most recent turns kept **as they are** (not summarised): that is where the agent is actively working, and summarising it would make the agent redo what it has just done. | Keep at least `2`-`3`. Raise it a little (`4`-`5`) if the agent "forgets" a very recent action right after a compression. | | ||
| 143 | -| `summaryMaxTokens` | `1200` | Largest summary generated to replace the old exchanges. The cap stops a runaway model from writing a summary that itself fills the window it was meant to empty. | For a small model, do not raise it much: a summary must stay compact. `1200` suits most cases; go down to `600`-`800` to save even more room. | | ||
| 144 | -| `prompt` | `""` (built-in prompt) | Replaces the prompt used to ask for the summary. | Leave it empty unless you have a specific need (e.g. a summary that keeps a particular format). | | ||
| 145 | -| `showStats` | `true` | Prints an information line after each compression (how many tokens were saved, etc.). | Leave it on: it shows that compression does its job. Turn it off only for a quieter output. | | ||
| 146 | - | ||
| 147 | -**Practical tip**: the summary is requested **without the tools and without "reasoning" mode**, precisely so that `summaryMaxTokens` is not wasted on thinking instead of a useful summary. | ||
| 148 | - | ||
| 149 | ---- | ||
| 150 | - | ||
| 151 | -## Summary: typical profiles | ||
| 152 | - | ||
| 153 | -| Situation | `firstTokenTimeout` | `watchdogTimeout` | `bashTimeout` | `maxTurns` | `maxOutput` | `context.enabled` | | ||
| 154 | -|---|---|---|---|---|---|---| | ||
| 155 | -| Small model (≤ 8B), short tasks/chat, no `bash` or commands under 20 s | `3m` (default) | `20s` (default) | `30s` (default) | `15` | `8000` | `true` | | ||
| 156 | -| Small/medium model, general coding agent | `5m` | `2m` (aligned on bashTimeout) | `2m` | `40` | `16000` | `true` | | ||
| 157 | -| Larger model or modest machine (CPU) | `10m` | `5m` | `5m` | `40`-`60` | `16000`-`24000` | `true` | | ||
| 158 | - | ||
| 159 | -In the first row, `watchdogTimeout` (20 s) is shorter than `bashTimeout` (30 s): those are the defaults, and they only fit when no command runs longer than 20 s. As soon as the agent runs longer commands, align the two as in the other rows (section 3). | ||
| 160 | - | ||
| 161 | -These profiles are starting points, not absolute truths: adjust them by watching how your model actually behaves (does it loop, is it cut too early, does the context fill up too fast). | ||
| 162 | - | ||
| 163 | ---- | ||
| 164 | - | ||
| 165 | -## 9. Sampling: how the model picks its words | ||
| 166 | - | ||
| 167 | -**In plain words**: "sampling" is the set of settings that control how the model picks the next word among all the ones it finds plausible. It decides whether the model is **precise and predictable** or **creative and varied**. Unlike the settings above (timeouts, quotas), sampling has no fixed structure in mini-me: it is a free list of keys (`sampling:` in the YAML) passed almost as is to the model's server. | ||
| 168 | - | ||
| 169 | -```yaml | ||
| 170 | -sampling: | ||
| 171 | - temperature: 0.0 | ||
| 172 | - top_p: 0.9 | ||
| 173 | - max_tokens: 4096 | ||
| 174 | -``` | ||
| 175 | - | ||
| 176 | -These are the only three keys mini-me sets by default. The others (`top_k`, `min_p`, `repeat_penalty`…) have no default: add them yourself if your server and model support them and you need them. | ||
| 177 | - | ||
| 178 | -### `temperature`: the "precise ↔ creative" dial | ||
| 179 | - | ||
| 180 | -**In plain words**: the closer it is to `0`, the more the model always picks the word it finds most likely (stable, reproducible answers, sometimes a little rigid). The higher it goes towards `1` (or beyond), the more it accepts less obvious words (more varied answers, but also more risk of mistakes and drift). | ||
| 181 | - | ||
| 182 | -- **mini-me default**: `0.0`, deliberately very low, because mini-me is designed as a **coding agent**, where precision and reproducibility matter, not creativity. | ||
| 183 | -- **How to set it for a small model**: | ||
| 184 | - - An agent that runs commands, writes code, follows strict instructions: **keep `0.0`-`0.2`**. A small model already makes more mistakes and loops more than a large one; a low temperature reduces that risk. | ||
| 185 | - - A conversational or creative agent, or one that must rephrase or brainstorm: go up to `0.5`-`0.8`. Beyond `0.8`, a small model more easily turns incoherent. | ||
| 186 | - | ||
| 187 | -### `top_p` (nucleus sampling): how wide the choice is | ||
| 188 | - | ||
| 189 | -**In plain words**: instead of considering every possible word, the model only looks at the smallest group of words whose combined probability reaches this share. `top_p: 0.9` means "only consider the words that together cover 90 % of the probability; ignore the long tail of unlikely ones". | ||
| 190 | - | ||
| 191 | -- **mini-me default**: `0.9`. | ||
| 192 | -- **How to set it**: together with a low `temperature`, `0.9` is already a good "safe" compromise for a small model. You can go down to `0.8` to cut odd detours further; there is no point going higher for a coding agent. | ||
| 193 | - | ||
| 194 | -### `top_k`: limiting the number of candidates (optional, no default in mini-me) | ||
| 195 | - | ||
| 196 | -**In plain words**: keep only the `k` most likely words at each step and ignore the rest, whatever `top_p` says. | ||
| 197 | - | ||
| 198 | -- **How to set it**: small models (often small Qwen, Gemma or Llama) do not all react to `top_k` the same way, and some model families explicitly recommend a value (for example `20`-`40`) in their model card. **Check the metadata or recommendations of the GGUF model you use** rather than guessing: a poorly chosen `top_k` can make a small model more repetitive or, on the contrary, more unstable. | ||
| 199 | - | ||
| 200 | -### `repeat_penalty` / `min_p`: against repetition (optional, no default in mini-me) | ||
| 201 | - | ||
| 202 | -**In plain words**: `repeat_penalty` penalises the model for reusing a word it used recently (useful against repetition loops, a classic weakness of small models). `min_p` is an alternative to `top_p` that drops the words whose probability is too low compared with the most likely word at that moment. | ||
| 203 | - | ||
| 204 | -- **How to set them**: these are typically the settings that **vary most from one model family to another**; there is no universal value. Good practice is to use the values the model card recommends (often in the GGUF metadata or the model's documentation) rather than improvising. If the agent repeats sentences or actions in a loop, this is often the first setting to adjust, together with mini-me's loop detector and `maxTurns` (section 5). | ||
| 205 | - | ||
| 206 | -### `max_tokens`: the longest an answer may be | ||
| 207 | - | ||
| 208 | -**In plain words**: how many tokens the model may generate in one answer before it is cut. | ||
| 209 | - | ||
| 210 | -- **mini-me default**: `4096`. | ||
| 211 | -- **How to set it**: for a small model with a small context window, check that `max_tokens` leaves enough room in the window for the prompt itself: `max_tokens` + prompt size must not exceed `contextWindow`. Lower it (`1024`-`2048`) if your answers must stay short (e.g. classification, extraction); keep the default for an agent that writes code or longer explanations. | ||
| 212 | - | ||
| 213 | -### In short: mini-me's sampling philosophy | ||
| 214 | - | ||
| 215 | -mini-me assumes that a **small local model is a coding agent first**, so its default sampling favours **precision and reproducibility** (`temperature: 0.0`) over creativity. It is the safest starting point to limit mistakes, hallucinated command results and loops; loosen it yourself if your use is more conversational or creative. | ||
| 216 | - | ||
| 217 | -> mini-me has no automatic "sampling profile" per model family today: the defaults are generic and deliberately conservative. When you switch models, check these settings again rather than keeping another model's out of habit. | ||
deleted
guides/raccourcis-clavier-tui.md +0 -121 | deleted file mode 100644 | ||
| @@ -1,121 +0,0 @@ | ||
| 1 | -# Raccourcis clavier de la fenêtre (`mm -tui`) | |
| 2 | - | |
| 3 | -*[English version](tui-keyboard-shortcuts.md)* | |
| 4 | - | |
| 5 | -> Toutes les touches que la fenêtre (`mm -tui`) comprend, regroupées selon ce que vous êtes en train de faire. **F1** en affiche une version courte dans la fenêtre. La barre d'état en bas rappelle toujours `F1 help · Ctrl-Y copy · F2 mouse · Ctrl-C quit`. | |
| 6 | - | |
| 7 | -## La fenêtre en deux parties | |
| 8 | - | |
| 9 | -Deux endroits peuvent recevoir les touches : la **zone de saisie** en bas, où vous tapez, et la **conversation** au-dessus. **Tab** fait passer le focus de l'un à l'autre. Au démarrage, le focus est sur la zone de saisie. Quand il est sur la conversation, les lettres ne font rien : appuyez sur Tab pour écrire à nouveau. | |
| 10 | - | |
| 11 | -## Écrire et envoyer | |
| 12 | - | |
| 13 | -| Touche | Effet | | |
| 14 | -|---|---| | |
| 15 | -| `Entrée` | Envoie le contenu de la zone. Une zone vide n'envoie rien. | | |
| 16 | -| `Ctrl-J` ou `Alt-Entrée` | Un saut de ligne dans la zone, sans envoyer. Un terminal ne distingue pas `Maj-Entrée` de `Entrée` : il envoie. | | |
| 17 | -| `←` `→` | Déplacent le curseur ; en début ou en fin de ligne, passent à la ligne précédente ou suivante. | | |
| 18 | -| `↑` `↓` | Passent à la rangée du dessus ou du dessous dans la zone — une ligne longue se replie sur plusieurs rangées. Sur la première rangée, `↑` rappelle votre question précédente (voir plus bas). | | |
| 19 | -| `Début` `Fin` | Début ou fin de la ligne. | | |
| 20 | -| `Retour arrière` `Suppr` | Effacent le caractère avant ou sous le curseur. Un collage replié (`[Pasted #1 · …]`) s'efface d'un bloc. | | |
| 21 | -| `Échap` | Quand rien ne tourne : vide la zone. | | |
| 22 | - | |
| 23 | -## Pendant que l'agent travaille | |
| 24 | - | |
| 25 | -| Touche | Effet | | |
| 26 | -|---|---| | |
| 27 | -| `Échap` | Arrête la réponse en cours (comme `/abort`) et affiche `🛑 Aborting…`. Appuyé à nouveau quand le tour ne s'arrête pas, il vous indique d'utiliser Ctrl-C. | | |
| 28 | -| `Ctrl-C` | Arrête la réponse en cours. Si elle a déjà reçu l'ordre de s'arrêter et ne l'a pas fait, `Ctrl-C` ferme mm. | | |
| 29 | -| `Entrée` | Arrête la réponse en cours et envoie ce que vous avez tapé une fois qu'elle est arrêtée : vous pouvez changer d'avis sans attendre. | | |
| 30 | - | |
| 31 | -## Rappeler une question précédente | |
| 32 | - | |
| 33 | -Demande `sessions.enabled: true` dans le YAML de l'agent. | |
| 34 | - | |
| 35 | -| Touche | Effet | | |
| 36 | -|---|---| | |
| 37 | -| `↑` (première rangée de la zone) | Remet votre question précédente dans la zone ; encore une fois pour celle d'avant — cette session d'abord, puis les sessions précédentes du projet. | | |
| 38 | -| `↓` (dernière rangée de la zone) | Revient vers la question la plus récente ; au-delà, rend ce que vous étiez en train de taper. | | |
| 39 | -| `Échap` | Efface la question rappelée, pour taper autre chose. | | |
| 40 | - | |
| 41 | -Une question rappelée peut être modifiée avant d'être envoyée. Sans rien à rappeler, `↑` et `↓` font défiler la conversation. | |
| 42 | - | |
| 43 | -## Se déplacer dans la conversation | |
| 44 | - | |
| 45 | -| Touche | Effet | | |
| 46 | -|---|---| | |
| 47 | -| `PgUp` `PgDn` | Une page vers le haut ou le bas, où que soit le focus. | | |
| 48 | -| `↑` `↓` | Une ligne, quand le focus est sur la conversation (`Tab`). | | |
| 49 | -| `Début` `Fin` | Haut ou bas de la conversation, quand le focus est dessus. `Fin` suit aussi à nouveau la réponse pendant qu'elle s'écrit. | | |
| 50 | -| Molette | Trois lignes vers le haut ou le bas — seulement après `F2` (voir plus bas). | | |
| 51 | -| `Ctrl-L` | Efface la conversation affichée. Ce dont l'agent se souvient n'est pas touché : c'est `/new` qui le fait. | | |
| 52 | - | |
| 53 | -## Compléter une commande, un fichier ou un skill | |
| 54 | - | |
| 55 | -Taper `/` au début de la zone, ou `@` ou `$` n'importe où, ouvre une liste de choix au-dessus de la zone : commandes, fichiers et dossiers, skills. | |
| 56 | - | |
| 57 | -| Touche | Effet | | |
| 58 | -|---|---| | |
| 59 | -| `↑` `↓` | Se déplacent dans la liste. | | |
| 60 | -| `Tab` | Complète avec le choix en surbrillance. | | |
| 61 | -| `Entrée` | Envoie quand ce que vous avez tapé est déjà complet ; sinon complète, comme `Tab`. | | |
| 62 | -| `Échap` | Ferme la liste jusqu'à ce que vous tapiez autre chose. | | |
| 63 | - | |
| 64 | -## Coller un texte long | |
| 65 | - | |
| 66 | -Collez comme d'habitude avec votre terminal (`Cmd-V`, `Ctrl-Maj-V`, le clic droit…). Un collage n'envoie jamais rien, même s'il contient des sauts de ligne. Au-delà de 3 lignes ou de 200 caractères, il s'affiche comme un seul jeton, `[Pasted #1 · 42 lines · 1.2k chars]` ; l'agent reçoit le texte complet. `Retour arrière` ou `Suppr` retire le jeton, et le texte avec lui. | |
| 67 | - | |
| 68 | -## Répondre à une permission | |
| 69 | - | |
| 70 | -Avec `yolo: false` (ou un outil MCP marqué `ask`), la zone est remplacée par une question comme `? bash: rm -rf build`. Seules ces touches marchent jusqu'à votre réponse : | |
| 71 | - | |
| 72 | -| Touche | Réponse | | |
| 73 | -|---|---| | |
| 74 | -| `a` | Autoriser cet appel, une fois. | | |
| 75 | -| `s` | Autoriser cet outil pour le reste de la session. | | |
| 76 | -| `r` ou `Échap` | Refuser cet appel. | | |
| 77 | -| `n` | Ne jamais autoriser cet outil dans cette session. | | |
| 78 | - | |
| 79 | -## Répondre aux questions de l'agent | |
| 80 | - | |
| 81 | -Quand l'agent vous pose une question (son outil `ask_user`), un petit formulaire remplace la zone. La ligne sous la question rappelle les touches. | |
| 82 | - | |
| 83 | -| Type de question | Touches | | |
| 84 | -|---|---| | |
| 85 | -| Un choix | `↑` `↓` (ou `Tab`) pour se déplacer, `Entrée` pour choisir — ou `1` à `9` pour choisir directement. | | |
| 86 | -| Plusieurs choix | `↑` `↓` pour se déplacer, `Espace` pour cocher ou décocher, `Entrée` pour envoyer (au moins un coché). | | |
| 87 | -| Oui ou non | `y` (ou `o`) oui, `n` non — ou `←` `→` puis `Entrée`. | | |
| 88 | -| Texte libre | Tapez, `Retour arrière` pour corriger, `Entrée` pour envoyer. | | |
| 89 | -| Toutes | `Échap` refuse de répondre. | | |
| 90 | - | |
| 91 | -## Copier, souris, aide, quitter | |
| 92 | - | |
| 93 | -| Touche | Effet | | |
| 94 | -|---|---| | |
| 95 | -| `Ctrl-Y` | Copie la dernière réponse dans le presse-papiers, en texte brut (comme `/copy` ; `/copy 2` celle d'avant, `/copy all` toute la conversation). | | |
| 96 | -| `F2` | Active ou désactive la capture de la souris. **Désactivée** (par défaut) : sélectionnez le texte à la souris comme dans n'importe quel terminal. **Activée** : la molette fait défiler la conversation, et `Maj`+glisser sélectionne. La barre d'état indique l'état. | | |
| 97 | -| `F1` | Les commandes et les principales touches, dans la conversation (comme `/help`). | | |
| 98 | -| `Ctrl-C` | Ferme mm quand rien ne tourne. `/quit` fait de même. | | |
| 99 | - | |
| 100 | -## La fenêtre de `mm init` | |
| 101 | - | |
| 102 | -`mm init` ouvre sa propre fenêtre, dans le même style, pour écrire un nouvel agent.yaml (voir [Créer un agent avec `mm init`](../docs/fr/how-to/create-an-agent.md)). | |
| 103 | - | |
| 104 | -| Touche | Effet | | |
| 105 | -|---|---| | |
| 106 | -| `↑` `↓` `Début` `Fin` | Se déplacent dans les choix ; l'aperçu à droite suit le choix surligné. | | |
| 107 | -| `Entrée` | Répond et passe à la question suivante ; sur le dernier écran, écrit le fichier. | | |
| 108 | -| `y` `n` | Répondent à la question oui ou non. | | |
| 109 | -| `Échap` | Revient d'une question en arrière, en reprenant sa réponse. | | |
| 110 | -| `PgUp` `PgDn` | Font défiler l'aperçu. | | |
| 111 | -| `Tab` | Sur un écran de moins de 100 colonnes : affiche l'aperçu à la place de la question, et inversement. | | |
| 112 | -| `←` `→` | Dans une réponse de texte (l'endpoint, la variable de la clé, le nom, le fichier) : déplacent le curseur ; la saisie s'insère là. `Début` `Fin` (ou `Ctrl-A` `Ctrl-E`) vont au début et à la fin ; `Retour arrière` efface avant le curseur, `Suppr` après. | | |
| 113 | -| `Ctrl-U` | Efface une réponse de texte. | | |
| 114 | -| `Ctrl-C` | Quitte sans rien écrire. | | |
| 115 | - | |
| 116 | -## Bon à savoir | |
| 117 | - | |
| 118 | -- **Les touches dépendent du terminal.** `Alt-Entrée`, `Début`, `Fin` et les touches de fonction dépendent de la façon dont le terminal les transmet ; sur un portable Mac, il faut souvent `Fn` pour `F1`, `F2`, `Début` et `Fin`. `Ctrl-J` marche toujours pour un saut de ligne. | |
| 119 | -- **La fenêtre a besoin d'un vrai terminal.** `mm -tui | tee log.txt`, ou toute exécution où l'entrée ou la sortie n'est pas un terminal, revient au mode ligne, où aucune de ces touches ne s'applique. | |
| 120 | - | |
| 121 | -Voir aussi : [Utiliser le mode fenêtre](../docs/fr/how-to/use-the-window-mode.md), [Commandes et touches (référence)](../docs/fr/reference/slash-commands.md). | |
| deleted file mode 100644 | |||
| @@ -1,121 +0,0 @@ | |||
| 1 | -# Raccourcis clavier de la fenêtre (`mm -tui`) | ||
| 2 | - | ||
| 3 | -*[English version](tui-keyboard-shortcuts.md)* | ||
| 4 | - | ||
| 5 | -> Toutes les touches que la fenêtre (`mm -tui`) comprend, regroupées selon ce que vous êtes en train de faire. **F1** en affiche une version courte dans la fenêtre. La barre d'état en bas rappelle toujours `F1 help · Ctrl-Y copy · F2 mouse · Ctrl-C quit`. | ||
| 6 | - | ||
| 7 | -## La fenêtre en deux parties | ||
| 8 | - | ||
| 9 | -Deux endroits peuvent recevoir les touches : la **zone de saisie** en bas, où vous tapez, et la **conversation** au-dessus. **Tab** fait passer le focus de l'un à l'autre. Au démarrage, le focus est sur la zone de saisie. Quand il est sur la conversation, les lettres ne font rien : appuyez sur Tab pour écrire à nouveau. | ||
| 10 | - | ||
| 11 | -## Écrire et envoyer | ||
| 12 | - | ||
| 13 | -| Touche | Effet | | ||
| 14 | -|---|---| | ||
| 15 | -| `Entrée` | Envoie le contenu de la zone. Une zone vide n'envoie rien. | | ||
| 16 | -| `Ctrl-J` ou `Alt-Entrée` | Un saut de ligne dans la zone, sans envoyer. Un terminal ne distingue pas `Maj-Entrée` de `Entrée` : il envoie. | | ||
| 17 | -| `←` `→` | Déplacent le curseur ; en début ou en fin de ligne, passent à la ligne précédente ou suivante. | | ||
| 18 | -| `↑` `↓` | Passent à la rangée du dessus ou du dessous dans la zone — une ligne longue se replie sur plusieurs rangées. Sur la première rangée, `↑` rappelle votre question précédente (voir plus bas). | | ||
| 19 | -| `Début` `Fin` | Début ou fin de la ligne. | | ||
| 20 | -| `Retour arrière` `Suppr` | Effacent le caractère avant ou sous le curseur. Un collage replié (`[Pasted #1 · …]`) s'efface d'un bloc. | | ||
| 21 | -| `Échap` | Quand rien ne tourne : vide la zone. | | ||
| 22 | - | ||
| 23 | -## Pendant que l'agent travaille | ||
| 24 | - | ||
| 25 | -| Touche | Effet | | ||
| 26 | -|---|---| | ||
| 27 | -| `Échap` | Arrête la réponse en cours (comme `/abort`) et affiche `🛑 Aborting…`. Appuyé à nouveau quand le tour ne s'arrête pas, il vous indique d'utiliser Ctrl-C. | | ||
| 28 | -| `Ctrl-C` | Arrête la réponse en cours. Si elle a déjà reçu l'ordre de s'arrêter et ne l'a pas fait, `Ctrl-C` ferme mm. | | ||
| 29 | -| `Entrée` | Arrête la réponse en cours et envoie ce que vous avez tapé une fois qu'elle est arrêtée : vous pouvez changer d'avis sans attendre. | | ||
| 30 | - | ||
| 31 | -## Rappeler une question précédente | ||
| 32 | - | ||
| 33 | -Demande `sessions.enabled: true` dans le YAML de l'agent. | ||
| 34 | - | ||
| 35 | -| Touche | Effet | | ||
| 36 | -|---|---| | ||
| 37 | -| `↑` (première rangée de la zone) | Remet votre question précédente dans la zone ; encore une fois pour celle d'avant — cette session d'abord, puis les sessions précédentes du projet. | | ||
| 38 | -| `↓` (dernière rangée de la zone) | Revient vers la question la plus récente ; au-delà, rend ce que vous étiez en train de taper. | | ||
| 39 | -| `Échap` | Efface la question rappelée, pour taper autre chose. | | ||
| 40 | - | ||
| 41 | -Une question rappelée peut être modifiée avant d'être envoyée. Sans rien à rappeler, `↑` et `↓` font défiler la conversation. | ||
| 42 | - | ||
| 43 | -## Se déplacer dans la conversation | ||
| 44 | - | ||
| 45 | -| Touche | Effet | | ||
| 46 | -|---|---| | ||
| 47 | -| `PgUp` `PgDn` | Une page vers le haut ou le bas, où que soit le focus. | | ||
| 48 | -| `↑` `↓` | Une ligne, quand le focus est sur la conversation (`Tab`). | | ||
| 49 | -| `Début` `Fin` | Haut ou bas de la conversation, quand le focus est dessus. `Fin` suit aussi à nouveau la réponse pendant qu'elle s'écrit. | | ||
| 50 | -| Molette | Trois lignes vers le haut ou le bas — seulement après `F2` (voir plus bas). | | ||
| 51 | -| `Ctrl-L` | Efface la conversation affichée. Ce dont l'agent se souvient n'est pas touché : c'est `/new` qui le fait. | | ||
| 52 | - | ||
| 53 | -## Compléter une commande, un fichier ou un skill | ||
| 54 | - | ||
| 55 | -Taper `/` au début de la zone, ou `@` ou `$` n'importe où, ouvre une liste de choix au-dessus de la zone : commandes, fichiers et dossiers, skills. | ||
| 56 | - | ||
| 57 | -| Touche | Effet | | ||
| 58 | -|---|---| | ||
| 59 | -| `↑` `↓` | Se déplacent dans la liste. | | ||
| 60 | -| `Tab` | Complète avec le choix en surbrillance. | | ||
| 61 | -| `Entrée` | Envoie quand ce que vous avez tapé est déjà complet ; sinon complète, comme `Tab`. | | ||
| 62 | -| `Échap` | Ferme la liste jusqu'à ce que vous tapiez autre chose. | | ||
| 63 | - | ||
| 64 | -## Coller un texte long | ||
| 65 | - | ||
| 66 | -Collez comme d'habitude avec votre terminal (`Cmd-V`, `Ctrl-Maj-V`, le clic droit…). Un collage n'envoie jamais rien, même s'il contient des sauts de ligne. Au-delà de 3 lignes ou de 200 caractères, il s'affiche comme un seul jeton, `[Pasted #1 · 42 lines · 1.2k chars]` ; l'agent reçoit le texte complet. `Retour arrière` ou `Suppr` retire le jeton, et le texte avec lui. | ||
| 67 | - | ||
| 68 | -## Répondre à une permission | ||
| 69 | - | ||
| 70 | -Avec `yolo: false` (ou un outil MCP marqué `ask`), la zone est remplacée par une question comme `? bash: rm -rf build`. Seules ces touches marchent jusqu'à votre réponse : | ||
| 71 | - | ||
| 72 | -| Touche | Réponse | | ||
| 73 | -|---|---| | ||
| 74 | -| `a` | Autoriser cet appel, une fois. | | ||
| 75 | -| `s` | Autoriser cet outil pour le reste de la session. | | ||
| 76 | -| `r` ou `Échap` | Refuser cet appel. | | ||
| 77 | -| `n` | Ne jamais autoriser cet outil dans cette session. | | ||
| 78 | - | ||
| 79 | -## Répondre aux questions de l'agent | ||
| 80 | - | ||
| 81 | -Quand l'agent vous pose une question (son outil `ask_user`), un petit formulaire remplace la zone. La ligne sous la question rappelle les touches. | ||
| 82 | - | ||
| 83 | -| Type de question | Touches | | ||
| 84 | -|---|---| | ||
| 85 | -| Un choix | `↑` `↓` (ou `Tab`) pour se déplacer, `Entrée` pour choisir — ou `1` à `9` pour choisir directement. | | ||
| 86 | -| Plusieurs choix | `↑` `↓` pour se déplacer, `Espace` pour cocher ou décocher, `Entrée` pour envoyer (au moins un coché). | | ||
| 87 | -| Oui ou non | `y` (ou `o`) oui, `n` non — ou `←` `→` puis `Entrée`. | | ||
| 88 | -| Texte libre | Tapez, `Retour arrière` pour corriger, `Entrée` pour envoyer. | | ||
| 89 | -| Toutes | `Échap` refuse de répondre. | | ||
| 90 | - | ||
| 91 | -## Copier, souris, aide, quitter | ||
| 92 | - | ||
| 93 | -| Touche | Effet | | ||
| 94 | -|---|---| | ||
| 95 | -| `Ctrl-Y` | Copie la dernière réponse dans le presse-papiers, en texte brut (comme `/copy` ; `/copy 2` celle d'avant, `/copy all` toute la conversation). | | ||
| 96 | -| `F2` | Active ou désactive la capture de la souris. **Désactivée** (par défaut) : sélectionnez le texte à la souris comme dans n'importe quel terminal. **Activée** : la molette fait défiler la conversation, et `Maj`+glisser sélectionne. La barre d'état indique l'état. | | ||
| 97 | -| `F1` | Les commandes et les principales touches, dans la conversation (comme `/help`). | | ||
| 98 | -| `Ctrl-C` | Ferme mm quand rien ne tourne. `/quit` fait de même. | | ||
| 99 | - | ||
| 100 | -## La fenêtre de `mm init` | ||
| 101 | - | ||
| 102 | -`mm init` ouvre sa propre fenêtre, dans le même style, pour écrire un nouvel agent.yaml (voir [Créer un agent avec `mm init`](../docs/fr/how-to/create-an-agent.md)). | ||
| 103 | - | ||
| 104 | -| Touche | Effet | | ||
| 105 | -|---|---| | ||
| 106 | -| `↑` `↓` `Début` `Fin` | Se déplacent dans les choix ; l'aperçu à droite suit le choix surligné. | | ||
| 107 | -| `Entrée` | Répond et passe à la question suivante ; sur le dernier écran, écrit le fichier. | | ||
| 108 | -| `y` `n` | Répondent à la question oui ou non. | | ||
| 109 | -| `Échap` | Revient d'une question en arrière, en reprenant sa réponse. | | ||
| 110 | -| `PgUp` `PgDn` | Font défiler l'aperçu. | | ||
| 111 | -| `Tab` | Sur un écran de moins de 100 colonnes : affiche l'aperçu à la place de la question, et inversement. | | ||
| 112 | -| `←` `→` | Dans une réponse de texte (l'endpoint, la variable de la clé, le nom, le fichier) : déplacent le curseur ; la saisie s'insère là. `Début` `Fin` (ou `Ctrl-A` `Ctrl-E`) vont au début et à la fin ; `Retour arrière` efface avant le curseur, `Suppr` après. | | ||
| 113 | -| `Ctrl-U` | Efface une réponse de texte. | | ||
| 114 | -| `Ctrl-C` | Quitte sans rien écrire. | | ||
| 115 | - | ||
| 116 | -## Bon à savoir | ||
| 117 | - | ||
| 118 | -- **Les touches dépendent du terminal.** `Alt-Entrée`, `Début`, `Fin` et les touches de fonction dépendent de la façon dont le terminal les transmet ; sur un portable Mac, il faut souvent `Fn` pour `F1`, `F2`, `Début` et `Fin`. `Ctrl-J` marche toujours pour un saut de ligne. | ||
| 119 | -- **La fenêtre a besoin d'un vrai terminal.** `mm -tui | tee log.txt`, ou toute exécution où l'entrée ou la sortie n'est pas un terminal, revient au mode ligne, où aucune de ces touches ne s'applique. | ||
| 120 | - | ||
| 121 | -Voir aussi : [Utiliser le mode fenêtre](../docs/fr/how-to/use-the-window-mode.md), [Commandes et touches (référence)](../docs/fr/reference/slash-commands.md). | ||
deleted
guides/reglages-agents-petits-modeles.md +0 -217 | deleted file mode 100644 | ||
| @@ -1,217 +0,0 @@ | ||
| 1 | -# Guide des réglages pour agents mini-me (en langage simple) | |
| 2 | - | |
| 3 | -*[English version](agent-settings-for-small-models.md)* | |
| 4 | - | |
| 5 | -> Ce guide explique, sans jargon, ce que fait chaque réglage de configuration d'un agent mini-me, pourquoi il existe, quelle est sa valeur par défaut, et comment le régler **quand on fait tourner un petit modèle de langage en local** (celui qui tient sur ton laptop, pas un modèle géant dans le cloud). | |
| 6 | - | |
| 7 | -## Pourquoi ces réglages existent | |
| 8 | - | |
| 9 | -Un petit modèle local (quelques milliards de paramètres, tournant sur un CPU/GPU grand public) n'a pas les mêmes défauts qu'un gros modèle cloud : | |
| 10 | - | |
| 11 | -- il est **lent** — surtout pour lire un long prompt (le "prompt processing"), | |
| 12 | -- il a une **mémoire (fenêtre de contexte) limitée** — souvent 8k à 32k tokens, parfois moins, | |
| 13 | -- il **boucle ou décroche** plus facilement (répète la même commande, oublie ce qu'il a déjà lu, part en vrille dans un raisonnement), | |
| 14 | -- il peut **halluciner** un résultat de commande qu'il n'a jamais vraiment exécuté. | |
| 15 | - | |
| 16 | -Les réglages ci-dessous sont les garde-fous qui compensent ça : ils disent à l'agent "arrête-toi si tu es trop lent", "ne garde pas tout en mémoire", "ne tourne pas en rond indéfiniment", "ne renvoie pas un pavé de texte qui bouche ta propre mémoire". | |
| 17 | - | |
| 18 | -Ils se règlent dans le fichier YAML de l'agent (`agent.*.yaml`), sous les mêmes noms de clés. | |
| 19 | - | |
| 20 | ---- | |
| 21 | - | |
| 22 | -## 1. `contextWindow` — la taille de la mémoire du modèle | |
| 23 | - | |
| 24 | -**En clair** : c'est la taille de la "mémoire de travail" du modèle, exprimée en tokens (un token ≈ 0,75 mot). Tout ce que l'agent a dit, lu, exécuté doit tenir dans cette mémoire. Quand elle est pleine, il faut faire de la place (voir section `context` plus bas). | |
| 25 | - | |
| 26 | -- **Valeur par défaut** : `0`, ce qui veut dire "je ne sais pas, demande au serveur". Si le serveur (llama.cpp, Docker Model Runner...) expose sa taille de contexte configurée, mini-me l'utilise automatiquement. | |
| 27 | -- **Comment la régler** : en général, **ne la fixe pas toi-même** si ton serveur peut la communiquer automatiquement — laisse `0`. Ne la renseigne à la main que si ton serveur ne la rapporte pas, et mets alors la vraie valeur que tu as configurée côté serveur (ex: `-c 8192` sur `llama-server` → `contextWindow: 8192`). | |
| 28 | -- **Pour un petit modèle** : les petits modèles sont souvent livrés avec une fenêtre annoncée de 32k ou plus, mais **en pratique, la qualité se dégrade bien avant** d'atteindre cette limite. Mieux vaut connaître la vraie valeur utilisable pour que les calculs de compression du contexte (section 8) soient fiables. | |
| 29 | - | |
| 30 | ---- | |
| 31 | - | |
| 32 | -## 2. `firstTokenTimeout` — le temps qu'on laisse au modèle pour *commencer* à répondre | |
| 33 | - | |
| 34 | -**En clair** : avant même que le modèle produise son premier mot, le serveur doit *lire* tout le prompt (la question + l'historique + les instructions). Sur un petit modèle local, lire un prompt de 20-30k tokens peut prendre plusieurs minutes. Ce réglage dit : "j'attends jusqu'à combien de temps avant de considérer que ça a planté ?" | |
| 35 | - | |
| 36 | -- **Valeur par défaut** : `3 minutes`. | |
| 37 | -- **Particularité** : si le serveur (llama.cpp) donne des nouvelles de sa progression de lecture pendant ce temps, le chronomètre est **remis à zéro** à chaque nouvelle. Donc en pratique, tant que le serveur progresse, ça ne coupera pas — ce timeout protège surtout contre un vrai blocage silencieux. | |
| 38 | -- **Comment la régler** : | |
| 39 | - - Modèle petit (≤ 8B) avec un bon GPU : la valeur par défaut (3 min) suffit généralement. | |
| 40 | - - Modèle plus gros (15-30B) ou machine modeste (CPU seul, peu de VRAM), ou prompts très longs (gros `AGENTS.md`, beaucoup d'historique) : monte à `5m` voire `10m`. | |
| 41 | - - Règle d'or : **jamais plus court que `watchdogTimeout`** (voir juste après) — sinon la protection n'a pas de sens. | |
| 42 | - | |
| 43 | ---- | |
| 44 | - | |
| 45 | -## 3. `watchdogTimeout` — le chien de garde pendant que le modèle *génère* | |
| 46 | - | |
| 47 | -**En clair** : une fois que le modèle a commencé à répondre (ou à utiliser un outil), ce réglage surveille qu'il continue à produire quelque chose régulièrement. S'il reste silencieux plus longtemps que cette durée *sans rien produire de nouveau*, mini-me considère que la connexion est bloquée et coupe. | |
| 48 | - | |
| 49 | -- **Valeur par défaut** : `20 secondes`. | |
| 50 | -- **Différence avec `firstTokenTimeout`** : `firstTokenTimeout` surveille le **démarrage** (lecture du prompt), `watchdogTimeout` surveille la **suite** (génération token par token, ou l'exécution d'un outil). C'est pour ça que `watchdogTimeout` est beaucoup plus court. | |
| 51 | -- **Comment la régler** : | |
| 52 | - - Si l'agent a accès à l'outil `bash` et que des commandes peuvent légitimement prendre du temps (build, tests, téléchargements), **monte ce timeout en même temps que `bashTimeout`** : pendant qu'une commande bash tourne, le chien de garde continue de compter, donc si `bashTimeout` vaut `2m`, `watchdogTimeout` doit valoir au moins `2m` aussi, sinon mini-me couperait la commande avant qu'elle finisse. | |
| 53 | - - Pour un usage "chat" simple sans gros outils : la valeur par défaut convient très bien, y compris sur un petit modèle lent (c'est la génération token-par-token qui compte, pas la vitesse globale). | |
| 54 | - | |
| 55 | ---- | |
| 56 | - | |
| 57 | -## 4. `bashTimeout` — combien de temps une commande shell a le droit de tourner | |
| 58 | - | |
| 59 | -**En clair** : quand l'agent exécute une commande (`bash`), c'est le temps maximum avant que mini-me la tue de force, même si elle n'a rien renvoyé. | |
| 60 | - | |
| 61 | -- **Valeur par défaut** : `30 secondes`. | |
| 62 | -- **Comment la régler** : | |
| 63 | - - Tâches rapides (lire un fichier, `git status`, `ls`) : le défaut de 30s est largement suffisant. | |
| 64 | - - Tâches lourdes attendues (compilation, tests, installation de dépendances, longue recherche) : augmente franchement, par exemple `2m`, `5m`, voire plus selon le projet. | |
| 65 | - - **Toujours augmenter `watchdogTimeout` en même temps** (voir section 3) — c'est le piège le plus courant : une commande se fait tuer par le chien de garde alors que `bashTimeout` lui laissait le temps. | |
| 66 | - - Ce réglage ne dépend pas vraiment de la taille du modèle, mais du type de projet sur lequel l'agent travaille. | |
| 67 | - | |
| 68 | ---- | |
| 69 | - | |
| 70 | -## 5. `maxTurns` — combien d'allers-retours modèle ↔ outils sont autorisés pour une seule question | |
| 71 | - | |
| 72 | -**En clair** : pour répondre à une question, l'agent peut faire plusieurs tours : "je lance une commande" → "je regarde le résultat" → "j'en lance une autre" → etc. Ce réglage plafonne le nombre de ces tours avant que mini-me arrête l'agent (pour éviter qu'il boucle à l'infini). | |
| 73 | - | |
| 74 | -- **Valeur par défaut** : `10`. | |
| 75 | -- **Valeur réellement utilisée dans les configurations livrées** : `40` — l'expérience montre que 10 est souvent trop bas pour des tâches de code réalistes avec un petit modèle, qui a besoin de plus d'itérations (relire, corriger, retenter) qu'un gros modèle. | |
| 76 | -- **Comment la régler** : | |
| 77 | - - Tâche étroite, une seule action attendue (répondre à une question factuelle, un seul appel d'outil) : `8` à `15` suffit, et ça protège mieux contre les boucles. | |
| 78 | - - Agent de développement généraliste (explorer du code, éditer, tester) : `40` à `60` est raisonnable, surtout avec un petit modèle qui a besoin de plusieurs essais. | |
| 79 | - - Plus le modèle est petit/faible, plus il risque de boucler sans jamais conclure — associe un `maxTurns` généreux à une bonne détection de boucle plutôt que de mettre une valeur énorme "au cas où". | |
| 80 | - | |
| 81 | ---- | |
| 82 | - | |
| 83 | -## 6. `maxOutput` — la taille maximale de ce qu'un outil peut renvoyer au modèle | |
| 84 | - | |
| 85 | -**En clair** : si une commande `bash` renvoie 500 000 caractères (un gros fichier de log, par exemple), on ne veut pas que ça remplisse d'un coup toute la mémoire du modèle. Ce réglage tronque le résultat avant de le montrer au modèle. | |
| 86 | - | |
| 87 | -- **Valeur par défaut** : `16000` caractères. | |
| 88 | -- **Comment ça tronque** : pas juste en coupant à la fin — mini-me garde le **début** du résultat et jusqu'à 2000 caractères de la **fin**, car souvent l'information utile (erreur, résumé) est à la fin d'une sortie longue. | |
| 89 | -- **Comment la régler** : | |
| 90 | - - Petit modèle à fenêtre de contexte réduite (8k-16k tokens) : **baisse** cette valeur, par exemple `4000` à `8000`, pour qu'une seule commande ne consomme pas un tiers de la mémoire disponible. | |
| 91 | - - Modèle avec une grande fenêtre de contexte, ou agent qui a vraiment besoin de voir des sorties complètes (ex: analyser un gros diff) : tu peux monter à `20000`-`30000`, mais garde en tête que chaque sortie "coûte" en tokens et accélère le moment où la compression du contexte (section 8) se déclenche. | |
| 92 | - | |
| 93 | ---- | |
| 94 | - | |
| 95 | -## 7. `agentsMd` — comment l'agent lit ses instructions de projet | |
| 96 | - | |
| 97 | -**En clair** : `AGENTS.md` (ou équivalent) contient les instructions propres au projet que l'agent doit suivre. Ce bloc de réglages contrôle si/comment ce fichier est chargé. | |
| 98 | - | |
| 99 | -```yaml | |
| 100 | -agentsMd: | |
| 101 | - enabled: true | |
| 102 | - path: "AGENTS.md" | |
| 103 | - maxChars: 0 | |
| 104 | -``` | |
| 105 | - | |
| 106 | -- **`enabled`** — défaut : `true`. Active la lecture automatique du fichier. | |
| 107 | -- **`path`** — défaut : `"AGENTS.md"`. Le nom/chemin du fichier à lire. | |
| 108 | -- **`maxChars`** — défaut : `0` (= pas de limite). | |
| 109 | - | |
| 110 | -### Le point important sur `maxChars` | |
| 111 | - | |
| 112 | -Ce n'est **pas** une troncature. Si le fichier `AGENTS.md` dépasse `maxChars` caractères, il n'est **pas coupé** — il est **entièrement ignoré** (le code source dit explicitement : couper au milieu risquerait de supprimer justement la règle qui compte). La bannière de démarrage l'indique (`skipped (too long)`) plutôt que de faire semblant d'avoir lu le fichier en entier. | |
| 113 | - | |
| 114 | -- **Comment la régler** : | |
| 115 | - - **Même sans `maxChars`, mini-me te prévient** : la bannière de démarrage avertit quand `AGENTS.md` occupe **20 % ou plus** d'une fenêtre de contexte connue (estimation : nombre de caractères ÷ 3,5). Avec un petit modèle, c'est le signe qu'il faut raccourcir le fichier. | |
| 116 | - - **`maxChars` est une limite stricte en plus de cet avertissement.** Avec un petit modèle à faible fenêtre, un `AGENTS.md` trop long peut consommer une grosse part de la mémoire avant même que la conversation commence. Fixer `maxChars` garantit qu'il ne la dépassera jamais : au-delà, le fichier est ignoré et la bannière le dit, et tu sais qu'il faut le raccourcir. | |
| 117 | - - Pour calculer une valeur : 20 % de la fenêtre × 3,5. Exemple : fenêtre de 8192 tokens → 20 % = 1638 tokens → environ `maxChars: 5700`. | |
| 118 | - - Si ton `AGENTS.md` est court (quelques centaines de lignes maximum) et que ton modèle a une fenêtre confortable (32k+), tu peux laisser `0`. | |
| 119 | - | |
| 120 | ---- | |
| 121 | - | |
| 122 | -## 8. `context` — la compression automatique de l'historique | |
| 123 | - | |
| 124 | -**En clair** : au fur et à mesure que la conversation avance, l'historique (questions, réponses, résultats de commandes) grandit. Sur un petit modèle à mémoire limitée, il arrive un moment où tout ne tient plus. Ce bloc décide **quand** et **comment** résumer automatiquement les anciens échanges pour faire de la place, sans perdre le fil. | |
| 125 | - | |
| 126 | -```yaml | |
| 127 | -context: | |
| 128 | - enabled: false | |
| 129 | - threshold: 75 | |
| 130 | - maxMessages: 80 | |
| 131 | - keepLastTurns: 3 | |
| 132 | - summaryMaxTokens: 1200 | |
| 133 | - prompt: "" | |
| 134 | - showStats: true | |
| 135 | -``` | |
| 136 | - | |
| 137 | -| Sous-réglage | Défaut | Ce qu'il fait | Comment le régler | | |
| 138 | -|---|---|---|---| | |
| 139 | -| `enabled` | `false` | Active la compression automatique. Même désactivé, tu peux toujours lancer une compression manuelle. | **Active-le (`true`) pour tout petit modèle local** — c'est la protection principale contre le "contexte plein" qui fait planter ou dégrader l'agent. | | |
| 140 | -| `threshold` | `75` (%) | Pourcentage de la fenêtre de contexte à partir duquel la compression se déclenche. 75 % laisse volontairement un quart de la mémoire libre pour la prochaine question, les résultats d'outils et la réponse. | Ne descends pas trop bas (tu compresserais trop souvent, donc tu perds en continuité) ; ne monte pas trop haut (tu risques de saturer avant que la compression ait pu agir). 70-80 % est une bonne plage. | | |
| 141 | -| `maxMessages` | `80` | Déclencheur de secours basé sur le *nombre* de messages, utilisé quand la taille de la fenêtre est inconnue (`contextWindow: 0` et serveur muet sur le sujet). Une commande = 2 messages (l'appel + le résultat), donc 80 ≈ 30 commandes d'historique. | Le code justifie 80 ainsi : c'est à peu près le moment où un modèle local de 12B commence à ralentir. Sur un modèle plus petit, tu peux baisser cette valeur si tu remarques que l'agent devient plus lent ou confus avant d'atteindre 80 messages. Mets `0` pour désactiver ce déclencheur si tu es sûr de connaître `contextWindow`. | | |
| 142 | -| `keepLastTurns` | `3` | Nombre de derniers tours de conversation gardés **intacts** (non résumés) — c'est là que l'agent "travaille" activement, le résumer le ferait rejouer ce qu'il vient juste de faire. | Garde au moins `2`-`3`. Monte-le un peu (`4`-`5`) si tu remarques que l'agent "oublie" une action toute récente juste après une compression. | | |
| 143 | -| `summaryMaxTokens` | `1200` | Taille maximale du résumé généré pour remplacer les vieux échanges. Ce plafond empêche un modèle qui dérape de produire un résumé qui lui-même remplit la fenêtre qu'on cherchait à vider. | Pour un petit modèle, ne monte pas trop ce chiffre : un résumé doit rester compact. `1200` convient à la plupart des cas ; descends à `600`-`800` si tu veux économiser encore plus de place. | | |
| 144 | -| `prompt` | `""` (prompt intégré) | Permet de remplacer le prompt utilisé pour demander le résumé. | Laisse vide sauf besoin spécifique (ex: vouloir que le résumé garde un format particulier). | | |
| 145 | -| `showStats` | `true` | Affiche une ligne d'info après chaque compression (combien de tokens économisés, etc.). | Laisse activé, c'est utile pour vérifier que la compression fait bien son travail — désactive seulement si tu veux une sortie plus silencieuse. | | |
| 146 | - | |
| 147 | -**Astuce pratique** : la compression envoie le résumé au modèle **sans les outils actifs et sans le mode "raisonnement"**, justement pour que `summaryMaxTokens` ne soit pas gaspillé en réflexion plutôt qu'en résumé utile. | |
| 148 | - | |
| 149 | ---- | |
| 150 | - | |
| 151 | -## Résumé — profils types | |
| 152 | - | |
| 153 | -| Situation | `firstTokenTimeout` | `watchdogTimeout` | `bashTimeout` | `maxTurns` | `maxOutput` | `context.enabled` | | |
| 154 | -|---|---|---|---|---|---|---| | |
| 155 | -| Petit modèle (≤ 8B), tâches courtes/chat, sans `bash` ou avec des commandes de moins de 20 s | `3m` (défaut) | `20s` (défaut) | `30s` (défaut) | `15` | `8000` | `true` | | |
| 156 | -| Petit/moyen modèle, agent de code généraliste | `5m` | `2m` (aligné sur bashTimeout) | `2m` | `40` | `16000` | `true` | | |
| 157 | -| Modèle plus gros ou machine modeste (CPU) | `10m` | `5m` | `5m` | `40`-`60` | `16000`-`24000` | `true` | | |
| 158 | - | |
| 159 | -Dans la première ligne, `watchdogTimeout` (20 s) est plus court que `bashTimeout` (30 s) : ce sont les valeurs par défaut, et elles ne conviennent que si aucune commande ne dure plus de 20 s. Dès que l'agent lance des commandes plus longues, aligne les deux comme dans les lignes suivantes (section 3). | |
| 160 | - | |
| 161 | -Ces profils sont des points de départ, pas des vérités absolues — ajuste en observant le comportement réel de ton modèle (est-ce qu'il boucle, est-ce qu'il se fait couper trop tôt, est-ce que le contexte se remplit trop vite). | |
| 162 | - | |
| 163 | ---- | |
| 164 | - | |
| 165 | -## 9. Section sampling — comment le modèle choisit ses mots | |
| 166 | - | |
| 167 | -**En clair** : le "sampling" (échantillonnage), ce sont les réglages qui contrôlent la façon dont le modèle pioche le mot suivant parmi toutes les possibilités qu'il juge plausibles. C'est la partie qui décide si le modèle est **précis et prévisible** ou **créatif et varié**. Contrairement aux réglages précédents (timeouts, quotas), le sampling n'a pas de struct figée dans mini-me : c'est une liste libre de clés (`sampling:` dans le YAML) transmise quasiment telle quelle au serveur du modèle. | |
| 168 | - | |
| 169 | -```yaml | |
| 170 | -sampling: | |
| 171 | - temperature: 0.0 | |
| 172 | - top_p: 0.9 | |
| 173 | - max_tokens: 4096 | |
| 174 | -``` | |
| 175 | - | |
| 176 | -Ce sont les trois seules clés définies par défaut dans mini-me. Les autres (`top_k`, `min_p`, `repeat_penalty`...) ne sont pas fixées par défaut — à toi de les ajouter si ton serveur/modèle les supporte et si tu en as besoin. | |
| 177 | - | |
| 178 | -### `temperature` — le curseur "précis ↔ créatif" | |
| 179 | - | |
| 180 | -**En clair** : plus elle est proche de `0`, plus le modèle choisit systématiquement le mot qu'il juge le plus probable (réponses stables, reproductibles, parfois un peu rigides). Plus elle monte vers `1` (ou au-delà), plus il accepte de piocher des mots moins évidents (réponses plus variées, mais aussi plus de risques d'erreurs ou d'écarts). | |
| 181 | - | |
| 182 | -- **Défaut mini-me** : `0.0` — volontairement très bas, car mini-me est pensé pour un **agent de code**, où on veut de la précision et de la reproductibilité, pas de la créativité. | |
| 183 | -- **Comment la régler pour un petit modèle** : | |
| 184 | - - Agent qui exécute des commandes, écrit du code, suit des instructions strictes : **garde `0.0`-`0.2`**. Un petit modèle est déjà plus sujet aux erreurs et aux boucles qu'un gros modèle ; une température basse réduit ce risque. | |
| 185 | - - Agent conversationnel, créatif, ou qui doit reformuler/brainstormer : monte à `0.5`-`0.8`. Au-delà de `0.8`, un petit modèle part plus facilement en incohérence. | |
| 186 | - | |
| 187 | -### `top_p` (nucleus sampling) — la largeur du choix | |
| 188 | - | |
| 189 | -**En clair** : au lieu de considérer tous les mots possibles, le modèle ne regarde que le plus petit groupe de mots dont la probabilité cumulée atteint ce pourcentage. `top_p: 0.9` veut dire "ne considère que les mots qui, ensemble, couvrent 90 % de la probabilité — ignore la longue traîne improbable". | |
| 190 | - | |
| 191 | -- **Défaut mini-me** : `0.9`. | |
| 192 | -- **Comment la régler** : combiné à une `temperature` basse, `0.9` est déjà un bon compromis "sûr" pour un petit modèle. Tu peux descendre à `0.8` si tu veux encore réduire les écarts bizarres ; inutile de monter plus haut pour un agent de code. | |
| 193 | - | |
| 194 | -### `top_k` — limiter le nombre de candidats (optionnel, pas de défaut dans mini-me) | |
| 195 | - | |
| 196 | -**En clair** : ne garde que les `k` mots les plus probables à chaque étape, et ignore tout le reste, quel que soit `top_p`. | |
| 197 | - | |
| 198 | -- **Comment la régler** : les petits modèles (souvent Qwen, Gemma, Llama en petites tailles) n'ont pas tous la même sensibilité à `top_k` — certaines familles de modèles recommandent explicitement une valeur (par exemple `20`-`40`) dans leur fiche technique. **Vérifie les métadonnées/recommandations du modèle GGUF que tu utilises** plutôt que de deviner : un `top_k` mal choisi peut rendre un petit modèle plus répétitif ou au contraire plus instable. | |
| 199 | - | |
| 200 | -### `repeat_penalty` / `min_p` — anti-répétition (optionnel, pas de défaut dans mini-me) | |
| 201 | - | |
| 202 | -**En clair** : `repeat_penalty` pénalise le modèle s'il réutilise un mot déjà employé récemment (utile contre les boucles de répétition, un défaut classique des petits modèles). `min_p` est une alternative à `top_p` qui élimine les mots dont la probabilité est trop faible par rapport au mot le plus probable du moment. | |
| 203 | - | |
| 204 | -- **Comment les régler** : ce sont typiquement les réglages qui **varient le plus d'une famille de modèle à l'autre** — il n'existe pas de valeur universelle. La bonne pratique est de reprendre les valeurs recommandées par la fiche du modèle (souvent indiquées dans les métadonnées GGUF ou la documentation du modèle) plutôt que d'improviser. Si l'agent répète des phrases ou des actions en boucle, c'est souvent le premier réglage à ajuster, avec le détecteur de boucle de mini-me et `maxTurns` (section 5). | |
| 205 | - | |
| 206 | -### `max_tokens` — la longueur maximale d'une réponse | |
| 207 | - | |
| 208 | -**En clair** : combien de tokens le modèle a le droit de générer en une seule réponse avant d'être coupé. | |
| 209 | - | |
| 210 | -- **Défaut mini-me** : `4096`. | |
| 211 | -- **Comment la régler** : pour un petit modèle avec une fenêtre de contexte réduite, vérifie que `max_tokens` laisse assez de place dans la fenêtre pour le prompt lui-même — `max_tokens` + taille du prompt ne doit pas dépasser `contextWindow`. Baisse-le (`1024`-`2048`) si tes réponses doivent rester courtes (ex: classification, extraction) ; garde la valeur par défaut pour un agent qui doit écrire du code ou des explications plus longues. | |
| 212 | - | |
| 213 | -### En résumé — philosophie du sampling dans mini-me | |
| 214 | - | |
| 215 | -mini-me part du principe qu'un **petit modèle local est un agent de code avant tout**, donc ses réglages de sampling par défaut privilégient la **précision et la reproductibilité** (`temperature: 0.0`) plutôt que la créativité. C'est le point de départ le plus sûr pour limiter les erreurs, les hallucinations de résultats de commandes et les boucles — quitte à l'assouplir toi-même si ton usage est plus conversationnel ou créatif. | |
| 216 | - | |
| 217 | -> Il n'existe pas aujourd'hui dans mini-me de "profil de sampling" automatique par famille de modèle — les valeurs par défaut sont génériques et volontairement conservatrices. Si tu changes de modèle, pense à revérifier ces réglages plutôt que de garder ceux d'un autre modèle par habitude. | |
| deleted file mode 100644 | |||
| @@ -1,217 +0,0 @@ | |||
| 1 | -# Guide des réglages pour agents mini-me (en langage simple) | ||
| 2 | - | ||
| 3 | -*[English version](agent-settings-for-small-models.md)* | ||
| 4 | - | ||
| 5 | -> Ce guide explique, sans jargon, ce que fait chaque réglage de configuration d'un agent mini-me, pourquoi il existe, quelle est sa valeur par défaut, et comment le régler **quand on fait tourner un petit modèle de langage en local** (celui qui tient sur ton laptop, pas un modèle géant dans le cloud). | ||
| 6 | - | ||
| 7 | -## Pourquoi ces réglages existent | ||
| 8 | - | ||
| 9 | -Un petit modèle local (quelques milliards de paramètres, tournant sur un CPU/GPU grand public) n'a pas les mêmes défauts qu'un gros modèle cloud : | ||
| 10 | - | ||
| 11 | -- il est **lent** — surtout pour lire un long prompt (le "prompt processing"), | ||
| 12 | -- il a une **mémoire (fenêtre de contexte) limitée** — souvent 8k à 32k tokens, parfois moins, | ||
| 13 | -- il **boucle ou décroche** plus facilement (répète la même commande, oublie ce qu'il a déjà lu, part en vrille dans un raisonnement), | ||
| 14 | -- il peut **halluciner** un résultat de commande qu'il n'a jamais vraiment exécuté. | ||
| 15 | - | ||
| 16 | -Les réglages ci-dessous sont les garde-fous qui compensent ça : ils disent à l'agent "arrête-toi si tu es trop lent", "ne garde pas tout en mémoire", "ne tourne pas en rond indéfiniment", "ne renvoie pas un pavé de texte qui bouche ta propre mémoire". | ||
| 17 | - | ||
| 18 | -Ils se règlent dans le fichier YAML de l'agent (`agent.*.yaml`), sous les mêmes noms de clés. | ||
| 19 | - | ||
| 20 | ---- | ||
| 21 | - | ||
| 22 | -## 1. `contextWindow` — la taille de la mémoire du modèle | ||
| 23 | - | ||
| 24 | -**En clair** : c'est la taille de la "mémoire de travail" du modèle, exprimée en tokens (un token ≈ 0,75 mot). Tout ce que l'agent a dit, lu, exécuté doit tenir dans cette mémoire. Quand elle est pleine, il faut faire de la place (voir section `context` plus bas). | ||
| 25 | - | ||
| 26 | -- **Valeur par défaut** : `0`, ce qui veut dire "je ne sais pas, demande au serveur". Si le serveur (llama.cpp, Docker Model Runner...) expose sa taille de contexte configurée, mini-me l'utilise automatiquement. | ||
| 27 | -- **Comment la régler** : en général, **ne la fixe pas toi-même** si ton serveur peut la communiquer automatiquement — laisse `0`. Ne la renseigne à la main que si ton serveur ne la rapporte pas, et mets alors la vraie valeur que tu as configurée côté serveur (ex: `-c 8192` sur `llama-server` → `contextWindow: 8192`). | ||
| 28 | -- **Pour un petit modèle** : les petits modèles sont souvent livrés avec une fenêtre annoncée de 32k ou plus, mais **en pratique, la qualité se dégrade bien avant** d'atteindre cette limite. Mieux vaut connaître la vraie valeur utilisable pour que les calculs de compression du contexte (section 8) soient fiables. | ||
| 29 | - | ||
| 30 | ---- | ||
| 31 | - | ||
| 32 | -## 2. `firstTokenTimeout` — le temps qu'on laisse au modèle pour *commencer* à répondre | ||
| 33 | - | ||
| 34 | -**En clair** : avant même que le modèle produise son premier mot, le serveur doit *lire* tout le prompt (la question + l'historique + les instructions). Sur un petit modèle local, lire un prompt de 20-30k tokens peut prendre plusieurs minutes. Ce réglage dit : "j'attends jusqu'à combien de temps avant de considérer que ça a planté ?" | ||
| 35 | - | ||
| 36 | -- **Valeur par défaut** : `3 minutes`. | ||
| 37 | -- **Particularité** : si le serveur (llama.cpp) donne des nouvelles de sa progression de lecture pendant ce temps, le chronomètre est **remis à zéro** à chaque nouvelle. Donc en pratique, tant que le serveur progresse, ça ne coupera pas — ce timeout protège surtout contre un vrai blocage silencieux. | ||
| 38 | -- **Comment la régler** : | ||
| 39 | - - Modèle petit (≤ 8B) avec un bon GPU : la valeur par défaut (3 min) suffit généralement. | ||
| 40 | - - Modèle plus gros (15-30B) ou machine modeste (CPU seul, peu de VRAM), ou prompts très longs (gros `AGENTS.md`, beaucoup d'historique) : monte à `5m` voire `10m`. | ||
| 41 | - - Règle d'or : **jamais plus court que `watchdogTimeout`** (voir juste après) — sinon la protection n'a pas de sens. | ||
| 42 | - | ||
| 43 | ---- | ||
| 44 | - | ||
| 45 | -## 3. `watchdogTimeout` — le chien de garde pendant que le modèle *génère* | ||
| 46 | - | ||
| 47 | -**En clair** : une fois que le modèle a commencé à répondre (ou à utiliser un outil), ce réglage surveille qu'il continue à produire quelque chose régulièrement. S'il reste silencieux plus longtemps que cette durée *sans rien produire de nouveau*, mini-me considère que la connexion est bloquée et coupe. | ||
| 48 | - | ||
| 49 | -- **Valeur par défaut** : `20 secondes`. | ||
| 50 | -- **Différence avec `firstTokenTimeout`** : `firstTokenTimeout` surveille le **démarrage** (lecture du prompt), `watchdogTimeout` surveille la **suite** (génération token par token, ou l'exécution d'un outil). C'est pour ça que `watchdogTimeout` est beaucoup plus court. | ||
| 51 | -- **Comment la régler** : | ||
| 52 | - - Si l'agent a accès à l'outil `bash` et que des commandes peuvent légitimement prendre du temps (build, tests, téléchargements), **monte ce timeout en même temps que `bashTimeout`** : pendant qu'une commande bash tourne, le chien de garde continue de compter, donc si `bashTimeout` vaut `2m`, `watchdogTimeout` doit valoir au moins `2m` aussi, sinon mini-me couperait la commande avant qu'elle finisse. | ||
| 53 | - - Pour un usage "chat" simple sans gros outils : la valeur par défaut convient très bien, y compris sur un petit modèle lent (c'est la génération token-par-token qui compte, pas la vitesse globale). | ||
| 54 | - | ||
| 55 | ---- | ||
| 56 | - | ||
| 57 | -## 4. `bashTimeout` — combien de temps une commande shell a le droit de tourner | ||
| 58 | - | ||
| 59 | -**En clair** : quand l'agent exécute une commande (`bash`), c'est le temps maximum avant que mini-me la tue de force, même si elle n'a rien renvoyé. | ||
| 60 | - | ||
| 61 | -- **Valeur par défaut** : `30 secondes`. | ||
| 62 | -- **Comment la régler** : | ||
| 63 | - - Tâches rapides (lire un fichier, `git status`, `ls`) : le défaut de 30s est largement suffisant. | ||
| 64 | - - Tâches lourdes attendues (compilation, tests, installation de dépendances, longue recherche) : augmente franchement, par exemple `2m`, `5m`, voire plus selon le projet. | ||
| 65 | - - **Toujours augmenter `watchdogTimeout` en même temps** (voir section 3) — c'est le piège le plus courant : une commande se fait tuer par le chien de garde alors que `bashTimeout` lui laissait le temps. | ||
| 66 | - - Ce réglage ne dépend pas vraiment de la taille du modèle, mais du type de projet sur lequel l'agent travaille. | ||
| 67 | - | ||
| 68 | ---- | ||
| 69 | - | ||
| 70 | -## 5. `maxTurns` — combien d'allers-retours modèle ↔ outils sont autorisés pour une seule question | ||
| 71 | - | ||
| 72 | -**En clair** : pour répondre à une question, l'agent peut faire plusieurs tours : "je lance une commande" → "je regarde le résultat" → "j'en lance une autre" → etc. Ce réglage plafonne le nombre de ces tours avant que mini-me arrête l'agent (pour éviter qu'il boucle à l'infini). | ||
| 73 | - | ||
| 74 | -- **Valeur par défaut** : `10`. | ||
| 75 | -- **Valeur réellement utilisée dans les configurations livrées** : `40` — l'expérience montre que 10 est souvent trop bas pour des tâches de code réalistes avec un petit modèle, qui a besoin de plus d'itérations (relire, corriger, retenter) qu'un gros modèle. | ||
| 76 | -- **Comment la régler** : | ||
| 77 | - - Tâche étroite, une seule action attendue (répondre à une question factuelle, un seul appel d'outil) : `8` à `15` suffit, et ça protège mieux contre les boucles. | ||
| 78 | - - Agent de développement généraliste (explorer du code, éditer, tester) : `40` à `60` est raisonnable, surtout avec un petit modèle qui a besoin de plusieurs essais. | ||
| 79 | - - Plus le modèle est petit/faible, plus il risque de boucler sans jamais conclure — associe un `maxTurns` généreux à une bonne détection de boucle plutôt que de mettre une valeur énorme "au cas où". | ||
| 80 | - | ||
| 81 | ---- | ||
| 82 | - | ||
| 83 | -## 6. `maxOutput` — la taille maximale de ce qu'un outil peut renvoyer au modèle | ||
| 84 | - | ||
| 85 | -**En clair** : si une commande `bash` renvoie 500 000 caractères (un gros fichier de log, par exemple), on ne veut pas que ça remplisse d'un coup toute la mémoire du modèle. Ce réglage tronque le résultat avant de le montrer au modèle. | ||
| 86 | - | ||
| 87 | -- **Valeur par défaut** : `16000` caractères. | ||
| 88 | -- **Comment ça tronque** : pas juste en coupant à la fin — mini-me garde le **début** du résultat et jusqu'à 2000 caractères de la **fin**, car souvent l'information utile (erreur, résumé) est à la fin d'une sortie longue. | ||
| 89 | -- **Comment la régler** : | ||
| 90 | - - Petit modèle à fenêtre de contexte réduite (8k-16k tokens) : **baisse** cette valeur, par exemple `4000` à `8000`, pour qu'une seule commande ne consomme pas un tiers de la mémoire disponible. | ||
| 91 | - - Modèle avec une grande fenêtre de contexte, ou agent qui a vraiment besoin de voir des sorties complètes (ex: analyser un gros diff) : tu peux monter à `20000`-`30000`, mais garde en tête que chaque sortie "coûte" en tokens et accélère le moment où la compression du contexte (section 8) se déclenche. | ||
| 92 | - | ||
| 93 | ---- | ||
| 94 | - | ||
| 95 | -## 7. `agentsMd` — comment l'agent lit ses instructions de projet | ||
| 96 | - | ||
| 97 | -**En clair** : `AGENTS.md` (ou équivalent) contient les instructions propres au projet que l'agent doit suivre. Ce bloc de réglages contrôle si/comment ce fichier est chargé. | ||
| 98 | - | ||
| 99 | -```yaml | ||
| 100 | -agentsMd: | ||
| 101 | - enabled: true | ||
| 102 | - path: "AGENTS.md" | ||
| 103 | - maxChars: 0 | ||
| 104 | -``` | ||
| 105 | - | ||
| 106 | -- **`enabled`** — défaut : `true`. Active la lecture automatique du fichier. | ||
| 107 | -- **`path`** — défaut : `"AGENTS.md"`. Le nom/chemin du fichier à lire. | ||
| 108 | -- **`maxChars`** — défaut : `0` (= pas de limite). | ||
| 109 | - | ||
| 110 | -### Le point important sur `maxChars` | ||
| 111 | - | ||
| 112 | -Ce n'est **pas** une troncature. Si le fichier `AGENTS.md` dépasse `maxChars` caractères, il n'est **pas coupé** — il est **entièrement ignoré** (le code source dit explicitement : couper au milieu risquerait de supprimer justement la règle qui compte). La bannière de démarrage l'indique (`skipped (too long)`) plutôt que de faire semblant d'avoir lu le fichier en entier. | ||
| 113 | - | ||
| 114 | -- **Comment la régler** : | ||
| 115 | - - **Même sans `maxChars`, mini-me te prévient** : la bannière de démarrage avertit quand `AGENTS.md` occupe **20 % ou plus** d'une fenêtre de contexte connue (estimation : nombre de caractères ÷ 3,5). Avec un petit modèle, c'est le signe qu'il faut raccourcir le fichier. | ||
| 116 | - - **`maxChars` est une limite stricte en plus de cet avertissement.** Avec un petit modèle à faible fenêtre, un `AGENTS.md` trop long peut consommer une grosse part de la mémoire avant même que la conversation commence. Fixer `maxChars` garantit qu'il ne la dépassera jamais : au-delà, le fichier est ignoré et la bannière le dit, et tu sais qu'il faut le raccourcir. | ||
| 117 | - - Pour calculer une valeur : 20 % de la fenêtre × 3,5. Exemple : fenêtre de 8192 tokens → 20 % = 1638 tokens → environ `maxChars: 5700`. | ||
| 118 | - - Si ton `AGENTS.md` est court (quelques centaines de lignes maximum) et que ton modèle a une fenêtre confortable (32k+), tu peux laisser `0`. | ||
| 119 | - | ||
| 120 | ---- | ||
| 121 | - | ||
| 122 | -## 8. `context` — la compression automatique de l'historique | ||
| 123 | - | ||
| 124 | -**En clair** : au fur et à mesure que la conversation avance, l'historique (questions, réponses, résultats de commandes) grandit. Sur un petit modèle à mémoire limitée, il arrive un moment où tout ne tient plus. Ce bloc décide **quand** et **comment** résumer automatiquement les anciens échanges pour faire de la place, sans perdre le fil. | ||
| 125 | - | ||
| 126 | -```yaml | ||
| 127 | -context: | ||
| 128 | - enabled: false | ||
| 129 | - threshold: 75 | ||
| 130 | - maxMessages: 80 | ||
| 131 | - keepLastTurns: 3 | ||
| 132 | - summaryMaxTokens: 1200 | ||
| 133 | - prompt: "" | ||
| 134 | - showStats: true | ||
| 135 | -``` | ||
| 136 | - | ||
| 137 | -| Sous-réglage | Défaut | Ce qu'il fait | Comment le régler | | ||
| 138 | -|---|---|---|---| | ||
| 139 | -| `enabled` | `false` | Active la compression automatique. Même désactivé, tu peux toujours lancer une compression manuelle. | **Active-le (`true`) pour tout petit modèle local** — c'est la protection principale contre le "contexte plein" qui fait planter ou dégrader l'agent. | | ||
| 140 | -| `threshold` | `75` (%) | Pourcentage de la fenêtre de contexte à partir duquel la compression se déclenche. 75 % laisse volontairement un quart de la mémoire libre pour la prochaine question, les résultats d'outils et la réponse. | Ne descends pas trop bas (tu compresserais trop souvent, donc tu perds en continuité) ; ne monte pas trop haut (tu risques de saturer avant que la compression ait pu agir). 70-80 % est une bonne plage. | | ||
| 141 | -| `maxMessages` | `80` | Déclencheur de secours basé sur le *nombre* de messages, utilisé quand la taille de la fenêtre est inconnue (`contextWindow: 0` et serveur muet sur le sujet). Une commande = 2 messages (l'appel + le résultat), donc 80 ≈ 30 commandes d'historique. | Le code justifie 80 ainsi : c'est à peu près le moment où un modèle local de 12B commence à ralentir. Sur un modèle plus petit, tu peux baisser cette valeur si tu remarques que l'agent devient plus lent ou confus avant d'atteindre 80 messages. Mets `0` pour désactiver ce déclencheur si tu es sûr de connaître `contextWindow`. | | ||
| 142 | -| `keepLastTurns` | `3` | Nombre de derniers tours de conversation gardés **intacts** (non résumés) — c'est là que l'agent "travaille" activement, le résumer le ferait rejouer ce qu'il vient juste de faire. | Garde au moins `2`-`3`. Monte-le un peu (`4`-`5`) si tu remarques que l'agent "oublie" une action toute récente juste après une compression. | | ||
| 143 | -| `summaryMaxTokens` | `1200` | Taille maximale du résumé généré pour remplacer les vieux échanges. Ce plafond empêche un modèle qui dérape de produire un résumé qui lui-même remplit la fenêtre qu'on cherchait à vider. | Pour un petit modèle, ne monte pas trop ce chiffre : un résumé doit rester compact. `1200` convient à la plupart des cas ; descends à `600`-`800` si tu veux économiser encore plus de place. | | ||
| 144 | -| `prompt` | `""` (prompt intégré) | Permet de remplacer le prompt utilisé pour demander le résumé. | Laisse vide sauf besoin spécifique (ex: vouloir que le résumé garde un format particulier). | | ||
| 145 | -| `showStats` | `true` | Affiche une ligne d'info après chaque compression (combien de tokens économisés, etc.). | Laisse activé, c'est utile pour vérifier que la compression fait bien son travail — désactive seulement si tu veux une sortie plus silencieuse. | | ||
| 146 | - | ||
| 147 | -**Astuce pratique** : la compression envoie le résumé au modèle **sans les outils actifs et sans le mode "raisonnement"**, justement pour que `summaryMaxTokens` ne soit pas gaspillé en réflexion plutôt qu'en résumé utile. | ||
| 148 | - | ||
| 149 | ---- | ||
| 150 | - | ||
| 151 | -## Résumé — profils types | ||
| 152 | - | ||
| 153 | -| Situation | `firstTokenTimeout` | `watchdogTimeout` | `bashTimeout` | `maxTurns` | `maxOutput` | `context.enabled` | | ||
| 154 | -|---|---|---|---|---|---|---| | ||
| 155 | -| Petit modèle (≤ 8B), tâches courtes/chat, sans `bash` ou avec des commandes de moins de 20 s | `3m` (défaut) | `20s` (défaut) | `30s` (défaut) | `15` | `8000` | `true` | | ||
| 156 | -| Petit/moyen modèle, agent de code généraliste | `5m` | `2m` (aligné sur bashTimeout) | `2m` | `40` | `16000` | `true` | | ||
| 157 | -| Modèle plus gros ou machine modeste (CPU) | `10m` | `5m` | `5m` | `40`-`60` | `16000`-`24000` | `true` | | ||
| 158 | - | ||
| 159 | -Dans la première ligne, `watchdogTimeout` (20 s) est plus court que `bashTimeout` (30 s) : ce sont les valeurs par défaut, et elles ne conviennent que si aucune commande ne dure plus de 20 s. Dès que l'agent lance des commandes plus longues, aligne les deux comme dans les lignes suivantes (section 3). | ||
| 160 | - | ||
| 161 | -Ces profils sont des points de départ, pas des vérités absolues — ajuste en observant le comportement réel de ton modèle (est-ce qu'il boucle, est-ce qu'il se fait couper trop tôt, est-ce que le contexte se remplit trop vite). | ||
| 162 | - | ||
| 163 | ---- | ||
| 164 | - | ||
| 165 | -## 9. Section sampling — comment le modèle choisit ses mots | ||
| 166 | - | ||
| 167 | -**En clair** : le "sampling" (échantillonnage), ce sont les réglages qui contrôlent la façon dont le modèle pioche le mot suivant parmi toutes les possibilités qu'il juge plausibles. C'est la partie qui décide si le modèle est **précis et prévisible** ou **créatif et varié**. Contrairement aux réglages précédents (timeouts, quotas), le sampling n'a pas de struct figée dans mini-me : c'est une liste libre de clés (`sampling:` dans le YAML) transmise quasiment telle quelle au serveur du modèle. | ||
| 168 | - | ||
| 169 | -```yaml | ||
| 170 | -sampling: | ||
| 171 | - temperature: 0.0 | ||
| 172 | - top_p: 0.9 | ||
| 173 | - max_tokens: 4096 | ||
| 174 | -``` | ||
| 175 | - | ||
| 176 | -Ce sont les trois seules clés définies par défaut dans mini-me. Les autres (`top_k`, `min_p`, `repeat_penalty`...) ne sont pas fixées par défaut — à toi de les ajouter si ton serveur/modèle les supporte et si tu en as besoin. | ||
| 177 | - | ||
| 178 | -### `temperature` — le curseur "précis ↔ créatif" | ||
| 179 | - | ||
| 180 | -**En clair** : plus elle est proche de `0`, plus le modèle choisit systématiquement le mot qu'il juge le plus probable (réponses stables, reproductibles, parfois un peu rigides). Plus elle monte vers `1` (ou au-delà), plus il accepte de piocher des mots moins évidents (réponses plus variées, mais aussi plus de risques d'erreurs ou d'écarts). | ||
| 181 | - | ||
| 182 | -- **Défaut mini-me** : `0.0` — volontairement très bas, car mini-me est pensé pour un **agent de code**, où on veut de la précision et de la reproductibilité, pas de la créativité. | ||
| 183 | -- **Comment la régler pour un petit modèle** : | ||
| 184 | - - Agent qui exécute des commandes, écrit du code, suit des instructions strictes : **garde `0.0`-`0.2`**. Un petit modèle est déjà plus sujet aux erreurs et aux boucles qu'un gros modèle ; une température basse réduit ce risque. | ||
| 185 | - - Agent conversationnel, créatif, ou qui doit reformuler/brainstormer : monte à `0.5`-`0.8`. Au-delà de `0.8`, un petit modèle part plus facilement en incohérence. | ||
| 186 | - | ||
| 187 | -### `top_p` (nucleus sampling) — la largeur du choix | ||
| 188 | - | ||
| 189 | -**En clair** : au lieu de considérer tous les mots possibles, le modèle ne regarde que le plus petit groupe de mots dont la probabilité cumulée atteint ce pourcentage. `top_p: 0.9` veut dire "ne considère que les mots qui, ensemble, couvrent 90 % de la probabilité — ignore la longue traîne improbable". | ||
| 190 | - | ||
| 191 | -- **Défaut mini-me** : `0.9`. | ||
| 192 | -- **Comment la régler** : combiné à une `temperature` basse, `0.9` est déjà un bon compromis "sûr" pour un petit modèle. Tu peux descendre à `0.8` si tu veux encore réduire les écarts bizarres ; inutile de monter plus haut pour un agent de code. | ||
| 193 | - | ||
| 194 | -### `top_k` — limiter le nombre de candidats (optionnel, pas de défaut dans mini-me) | ||
| 195 | - | ||
| 196 | -**En clair** : ne garde que les `k` mots les plus probables à chaque étape, et ignore tout le reste, quel que soit `top_p`. | ||
| 197 | - | ||
| 198 | -- **Comment la régler** : les petits modèles (souvent Qwen, Gemma, Llama en petites tailles) n'ont pas tous la même sensibilité à `top_k` — certaines familles de modèles recommandent explicitement une valeur (par exemple `20`-`40`) dans leur fiche technique. **Vérifie les métadonnées/recommandations du modèle GGUF que tu utilises** plutôt que de deviner : un `top_k` mal choisi peut rendre un petit modèle plus répétitif ou au contraire plus instable. | ||
| 199 | - | ||
| 200 | -### `repeat_penalty` / `min_p` — anti-répétition (optionnel, pas de défaut dans mini-me) | ||
| 201 | - | ||
| 202 | -**En clair** : `repeat_penalty` pénalise le modèle s'il réutilise un mot déjà employé récemment (utile contre les boucles de répétition, un défaut classique des petits modèles). `min_p` est une alternative à `top_p` qui élimine les mots dont la probabilité est trop faible par rapport au mot le plus probable du moment. | ||
| 203 | - | ||
| 204 | -- **Comment les régler** : ce sont typiquement les réglages qui **varient le plus d'une famille de modèle à l'autre** — il n'existe pas de valeur universelle. La bonne pratique est de reprendre les valeurs recommandées par la fiche du modèle (souvent indiquées dans les métadonnées GGUF ou la documentation du modèle) plutôt que d'improviser. Si l'agent répète des phrases ou des actions en boucle, c'est souvent le premier réglage à ajuster, avec le détecteur de boucle de mini-me et `maxTurns` (section 5). | ||
| 205 | - | ||
| 206 | -### `max_tokens` — la longueur maximale d'une réponse | ||
| 207 | - | ||
| 208 | -**En clair** : combien de tokens le modèle a le droit de générer en une seule réponse avant d'être coupé. | ||
| 209 | - | ||
| 210 | -- **Défaut mini-me** : `4096`. | ||
| 211 | -- **Comment la régler** : pour un petit modèle avec une fenêtre de contexte réduite, vérifie que `max_tokens` laisse assez de place dans la fenêtre pour le prompt lui-même — `max_tokens` + taille du prompt ne doit pas dépasser `contextWindow`. Baisse-le (`1024`-`2048`) si tes réponses doivent rester courtes (ex: classification, extraction) ; garde la valeur par défaut pour un agent qui doit écrire du code ou des explications plus longues. | ||
| 212 | - | ||
| 213 | -### En résumé — philosophie du sampling dans mini-me | ||
| 214 | - | ||
| 215 | -mini-me part du principe qu'un **petit modèle local est un agent de code avant tout**, donc ses réglages de sampling par défaut privilégient la **précision et la reproductibilité** (`temperature: 0.0`) plutôt que la créativité. C'est le point de départ le plus sûr pour limiter les erreurs, les hallucinations de résultats de commandes et les boucles — quitte à l'assouplir toi-même si ton usage est plus conversationnel ou créatif. | ||
| 216 | - | ||
| 217 | -> Il n'existe pas aujourd'hui dans mini-me de "profil de sampling" automatique par famille de modèle — les valeurs par défaut sont génériques et volontairement conservatrices. Si tu changes de modèle, pense à revérifier ces réglages plutôt que de garder ceux d'un autre modèle par habitude. | ||
deleted
guides/tui-keyboard-shortcuts.md +0 -121 | deleted file mode 100644 | ||
| @@ -1,121 +0,0 @@ | ||
| 1 | -# Keyboard shortcuts of the window (`mm -tui`) | |
| 2 | - | |
| 3 | -*[Version française](raccourcis-clavier-tui.md)* | |
| 4 | - | |
| 5 | -> Every key the window (`mm -tui`) understands, grouped by what you are doing. **F1** shows a short version inside the window. The status bar at the bottom always shows `F1 help · Ctrl-Y copy · F2 mouse · Ctrl-C quit`. | |
| 6 | - | |
| 7 | -## The window in two parts | |
| 8 | - | |
| 9 | -The window has two places that can take the keys: the **box** at the bottom, where you type, and the **conversation** above it. **Tab** moves the focus from one to the other. At start-up the focus is on the box. While the focus is on the conversation, letters do nothing: press Tab to type again. | |
| 10 | - | |
| 11 | -## Type and send | |
| 12 | - | |
| 13 | -| Key | What it does | | |
| 14 | -|---|---| | |
| 15 | -| `Enter` | Sends what is in the box. An empty box sends nothing. | | |
| 16 | -| `Ctrl-J` or `Alt-Enter` | A new line in the box, without sending. `Shift-Enter` cannot be told apart from `Enter` by a terminal, so it sends. | | |
| 17 | -| `←` `→` | Move the cursor; at the start or end of a line, go to the previous or next line. | | |
| 18 | -| `↑` `↓` | Move to the row above or below in the box — a long line wraps over several rows. On the first row, `↑` recalls your previous question (see below). | | |
| 19 | -| `Home` `End` | Start or end of the line. | | |
| 20 | -| `Backspace` `Delete` | Delete the character before or under the cursor. A collapsed paste (`[Pasted #1 · …]`) is deleted whole. | | |
| 21 | -| `Esc` | When nothing is running: clears the box. | | |
| 22 | - | |
| 23 | -## While the agent is working | |
| 24 | - | |
| 25 | -| Key | What it does | | |
| 26 | -|---|---| | |
| 27 | -| `Esc` | Stops the answer in progress (same as `/abort`) and says `🛑 Aborting…`. Pressed again when the turn does not stop, it tells you to use Ctrl-C. | | |
| 28 | -| `Ctrl-C` | Stops the answer in progress. If it has already been asked to stop and has not, `Ctrl-C` closes mm. | | |
| 29 | -| `Enter` | Stops the answer in progress and sends what you typed once it has stopped: you can change your mind without waiting. | | |
| 30 | - | |
| 31 | -## Recall an earlier question | |
| 32 | - | |
| 33 | -Needs `sessions.enabled: true` in the agent's YAML. | |
| 34 | - | |
| 35 | -| Key | What it does | | |
| 36 | -|---|---| | |
| 37 | -| `↑` (first row of the box) | Puts your previous question in the box; again for the one before — this session first, then the project's earlier sessions. | | |
| 38 | -| `↓` (last row of the box) | Goes back towards the newest question; past it, gives back what you were typing. | | |
| 39 | -| `Esc` | Clears the recalled question, to type something else. | | |
| 40 | - | |
| 41 | -A recalled question can be edited before you send it. With nothing to recall, `↑` and `↓` scroll the conversation instead. | |
| 42 | - | |
| 43 | -## Move through the conversation | |
| 44 | - | |
| 45 | -| Key | What it does | | |
| 46 | -|---|---| | |
| 47 | -| `PgUp` `PgDn` | One page up or down, wherever the focus is. | | |
| 48 | -| `↑` `↓` | One line, when the focus is on the conversation (`Tab`). | | |
| 49 | -| `Home` `End` | Top or bottom of the conversation, when the focus is on it. `End` also follows the answer again as it is written. | | |
| 50 | -| Mouse wheel | Three lines up or down — only after `F2` (see below). | | |
| 51 | -| `Ctrl-L` | Clears the displayed conversation. What the agent remembers is not touched: `/new` does that. | | |
| 52 | - | |
| 53 | -## Complete a command, a file or a skill | |
| 54 | - | |
| 55 | -Typing `/` at the start of the box, `@` or `$` anywhere opens a list of choices above the box: commands, files and folders, skills. | |
| 56 | - | |
| 57 | -| Key | What it does | | |
| 58 | -|---|---| | |
| 59 | -| `↑` `↓` | Move in the list. | | |
| 60 | -| `Tab` | Completes with the highlighted choice. | | |
| 61 | -| `Enter` | Sends when what you typed is already complete; otherwise completes, like `Tab`. | | |
| 62 | -| `Esc` | Closes the list until you type something else. | | |
| 63 | - | |
| 64 | -## Paste long text | |
| 65 | - | |
| 66 | -Paste as usual with your terminal (`Cmd-V`, `Ctrl-Shift-V`, the right click…). A paste never sends anything, even when it holds line breaks. Longer than 3 lines or 200 characters, it shows as one token, `[Pasted #1 · 42 lines · 1.2k chars]`; the agent receives the whole text. `Backspace` or `Delete` removes the token, and the text with it. | |
| 67 | - | |
| 68 | -## Answer a permission | |
| 69 | - | |
| 70 | -With `yolo: false` (or an MCP tool marked `ask`), the box is replaced by a question such as `? bash: rm -rf build`. Only these keys work until you answer: | |
| 71 | - | |
| 72 | -| Key | Answer | | |
| 73 | -|---|---| | |
| 74 | -| `a` | Allow this call, once. | | |
| 75 | -| `s` | Allow this tool for the rest of the session. | | |
| 76 | -| `r` or `Esc` | Refuse this call. | | |
| 77 | -| `n` | Never allow this tool in this session. | | |
| 78 | - | |
| 79 | -## Answer the agent's questions | |
| 80 | - | |
| 81 | -When the agent asks you something (its `ask_user` tool), a small form replaces the box. The line under the question reminds you of the keys. | |
| 82 | - | |
| 83 | -| Kind of question | Keys | | |
| 84 | -|---|---| | |
| 85 | -| Pick one | `↑` `↓` (or `Tab`) to move, `Enter` to choose — or `1` to `9` to choose directly. | | |
| 86 | -| Pick several | `↑` `↓` to move, `Space` to tick or untick, `Enter` to send (at least one ticked). | | |
| 87 | -| Yes or no | `y` (or `o`) yes, `n` no — or `←` `→` then `Enter`. | | |
| 88 | -| Free text | Type, `Backspace` to correct, `Enter` to send. | | |
| 89 | -| Any | `Esc` declines to answer. | | |
| 90 | - | |
| 91 | -## Copy, mouse, help, quit | |
| 92 | - | |
| 93 | -| Key | What it does | | |
| 94 | -|---|---| | |
| 95 | -| `Ctrl-Y` | Copies the last answer to the clipboard, as plain text (same as `/copy`; `/copy 2` the one before, `/copy all` the whole conversation). | | |
| 96 | -| `F2` | Turns mouse capture on or off. **Off** (the default): select text with the mouse as in any terminal. **On**: the wheel scrolls the conversation, and `Shift`+drag selects. The status bar says which. | | |
| 97 | -| `F1` | The commands and the main keys, in the conversation (same as `/help`). | | |
| 98 | -| `Ctrl-C` | Closes mm when nothing is running. `/quit` does the same. | | |
| 99 | - | |
| 100 | -## The `mm init` window | |
| 101 | - | |
| 102 | -`mm init` opens a window of its own, in the same style, to write a new agent.yaml (see [Create an agent with `mm init`](../docs/en/how-to/create-an-agent.md)). | |
| 103 | - | |
| 104 | -| Key | What it does | | |
| 105 | -|---|---| | |
| 106 | -| `↑` `↓` `Home` `End` | Move through the choices; the preview on the right follows the highlighted one. | | |
| 107 | -| `Enter` | Answer and go to the next question; on the last screen, write the file. | | |
| 108 | -| `y` `n` | Answer the yes-or-no question. | | |
| 109 | -| `Esc` | Go back one question, taking its answer back. | | |
| 110 | -| `PgUp` `PgDn` | Scroll the preview. | | |
| 111 | -| `Tab` | On a screen narrower than 100 columns: show the preview in place of the question, and back. | | |
| 112 | -| `←` `→` | In a text answer (the endpoint, the key's variable, the name, the file): move the cursor; typing inserts there. `Home` `End` (or `Ctrl-A` `Ctrl-E`) go to the start and the end; `Backspace` deletes before the cursor, `Delete` after it. | | |
| 113 | -| `Ctrl-U` | Clear a text answer. | | |
| 114 | -| `Ctrl-C` | Quit without writing anything. | | |
| 115 | - | |
| 116 | -## Good to know | |
| 117 | - | |
| 118 | -- **Keys depend on the terminal.** `Alt-Enter`, `Home`, `End` and the function keys depend on how the terminal reports them; on a Mac laptop, `Fn` is often needed for `F1`, `F2`, `Home` and `End`. `Ctrl-J` always works for a new line. | |
| 119 | -- **The window needs a real terminal.** `mm -tui | tee log.txt`, or any run where the input or the output is not a terminal, falls back to the line mode, where none of these keys apply. | |
| 120 | - | |
| 121 | -See also: [How to use the window mode](../docs/en/how-to/use-the-window-mode.md), [Slash commands and keys (reference)](../docs/en/reference/slash-commands.md). | |
| deleted file mode 100644 | |||
| @@ -1,121 +0,0 @@ | |||
| 1 | -# Keyboard shortcuts of the window (`mm -tui`) | ||
| 2 | - | ||
| 3 | -*[Version française](raccourcis-clavier-tui.md)* | ||
| 4 | - | ||
| 5 | -> Every key the window (`mm -tui`) understands, grouped by what you are doing. **F1** shows a short version inside the window. The status bar at the bottom always shows `F1 help · Ctrl-Y copy · F2 mouse · Ctrl-C quit`. | ||
| 6 | - | ||
| 7 | -## The window in two parts | ||
| 8 | - | ||
| 9 | -The window has two places that can take the keys: the **box** at the bottom, where you type, and the **conversation** above it. **Tab** moves the focus from one to the other. At start-up the focus is on the box. While the focus is on the conversation, letters do nothing: press Tab to type again. | ||
| 10 | - | ||
| 11 | -## Type and send | ||
| 12 | - | ||
| 13 | -| Key | What it does | | ||
| 14 | -|---|---| | ||
| 15 | -| `Enter` | Sends what is in the box. An empty box sends nothing. | | ||
| 16 | -| `Ctrl-J` or `Alt-Enter` | A new line in the box, without sending. `Shift-Enter` cannot be told apart from `Enter` by a terminal, so it sends. | | ||
| 17 | -| `←` `→` | Move the cursor; at the start or end of a line, go to the previous or next line. | | ||
| 18 | -| `↑` `↓` | Move to the row above or below in the box — a long line wraps over several rows. On the first row, `↑` recalls your previous question (see below). | | ||
| 19 | -| `Home` `End` | Start or end of the line. | | ||
| 20 | -| `Backspace` `Delete` | Delete the character before or under the cursor. A collapsed paste (`[Pasted #1 · …]`) is deleted whole. | | ||
| 21 | -| `Esc` | When nothing is running: clears the box. | | ||
| 22 | - | ||
| 23 | -## While the agent is working | ||
| 24 | - | ||
| 25 | -| Key | What it does | | ||
| 26 | -|---|---| | ||
| 27 | -| `Esc` | Stops the answer in progress (same as `/abort`) and says `🛑 Aborting…`. Pressed again when the turn does not stop, it tells you to use Ctrl-C. | | ||
| 28 | -| `Ctrl-C` | Stops the answer in progress. If it has already been asked to stop and has not, `Ctrl-C` closes mm. | | ||
| 29 | -| `Enter` | Stops the answer in progress and sends what you typed once it has stopped: you can change your mind without waiting. | | ||
| 30 | - | ||
| 31 | -## Recall an earlier question | ||
| 32 | - | ||
| 33 | -Needs `sessions.enabled: true` in the agent's YAML. | ||
| 34 | - | ||
| 35 | -| Key | What it does | | ||
| 36 | -|---|---| | ||
| 37 | -| `↑` (first row of the box) | Puts your previous question in the box; again for the one before — this session first, then the project's earlier sessions. | | ||
| 38 | -| `↓` (last row of the box) | Goes back towards the newest question; past it, gives back what you were typing. | | ||
| 39 | -| `Esc` | Clears the recalled question, to type something else. | | ||
| 40 | - | ||
| 41 | -A recalled question can be edited before you send it. With nothing to recall, `↑` and `↓` scroll the conversation instead. | ||
| 42 | - | ||
| 43 | -## Move through the conversation | ||
| 44 | - | ||
| 45 | -| Key | What it does | | ||
| 46 | -|---|---| | ||
| 47 | -| `PgUp` `PgDn` | One page up or down, wherever the focus is. | | ||
| 48 | -| `↑` `↓` | One line, when the focus is on the conversation (`Tab`). | | ||
| 49 | -| `Home` `End` | Top or bottom of the conversation, when the focus is on it. `End` also follows the answer again as it is written. | | ||
| 50 | -| Mouse wheel | Three lines up or down — only after `F2` (see below). | | ||
| 51 | -| `Ctrl-L` | Clears the displayed conversation. What the agent remembers is not touched: `/new` does that. | | ||
| 52 | - | ||
| 53 | -## Complete a command, a file or a skill | ||
| 54 | - | ||
| 55 | -Typing `/` at the start of the box, `@` or `$` anywhere opens a list of choices above the box: commands, files and folders, skills. | ||
| 56 | - | ||
| 57 | -| Key | What it does | | ||
| 58 | -|---|---| | ||
| 59 | -| `↑` `↓` | Move in the list. | | ||
| 60 | -| `Tab` | Completes with the highlighted choice. | | ||
| 61 | -| `Enter` | Sends when what you typed is already complete; otherwise completes, like `Tab`. | | ||
| 62 | -| `Esc` | Closes the list until you type something else. | | ||
| 63 | - | ||
| 64 | -## Paste long text | ||
| 65 | - | ||
| 66 | -Paste as usual with your terminal (`Cmd-V`, `Ctrl-Shift-V`, the right click…). A paste never sends anything, even when it holds line breaks. Longer than 3 lines or 200 characters, it shows as one token, `[Pasted #1 · 42 lines · 1.2k chars]`; the agent receives the whole text. `Backspace` or `Delete` removes the token, and the text with it. | ||
| 67 | - | ||
| 68 | -## Answer a permission | ||
| 69 | - | ||
| 70 | -With `yolo: false` (or an MCP tool marked `ask`), the box is replaced by a question such as `? bash: rm -rf build`. Only these keys work until you answer: | ||
| 71 | - | ||
| 72 | -| Key | Answer | | ||
| 73 | -|---|---| | ||
| 74 | -| `a` | Allow this call, once. | | ||
| 75 | -| `s` | Allow this tool for the rest of the session. | | ||
| 76 | -| `r` or `Esc` | Refuse this call. | | ||
| 77 | -| `n` | Never allow this tool in this session. | | ||
| 78 | - | ||
| 79 | -## Answer the agent's questions | ||
| 80 | - | ||
| 81 | -When the agent asks you something (its `ask_user` tool), a small form replaces the box. The line under the question reminds you of the keys. | ||
| 82 | - | ||
| 83 | -| Kind of question | Keys | | ||
| 84 | -|---|---| | ||
| 85 | -| Pick one | `↑` `↓` (or `Tab`) to move, `Enter` to choose — or `1` to `9` to choose directly. | | ||
| 86 | -| Pick several | `↑` `↓` to move, `Space` to tick or untick, `Enter` to send (at least one ticked). | | ||
| 87 | -| Yes or no | `y` (or `o`) yes, `n` no — or `←` `→` then `Enter`. | | ||
| 88 | -| Free text | Type, `Backspace` to correct, `Enter` to send. | | ||
| 89 | -| Any | `Esc` declines to answer. | | ||
| 90 | - | ||
| 91 | -## Copy, mouse, help, quit | ||
| 92 | - | ||
| 93 | -| Key | What it does | | ||
| 94 | -|---|---| | ||
| 95 | -| `Ctrl-Y` | Copies the last answer to the clipboard, as plain text (same as `/copy`; `/copy 2` the one before, `/copy all` the whole conversation). | | ||
| 96 | -| `F2` | Turns mouse capture on or off. **Off** (the default): select text with the mouse as in any terminal. **On**: the wheel scrolls the conversation, and `Shift`+drag selects. The status bar says which. | | ||
| 97 | -| `F1` | The commands and the main keys, in the conversation (same as `/help`). | | ||
| 98 | -| `Ctrl-C` | Closes mm when nothing is running. `/quit` does the same. | | ||
| 99 | - | ||
| 100 | -## The `mm init` window | ||
| 101 | - | ||
| 102 | -`mm init` opens a window of its own, in the same style, to write a new agent.yaml (see [Create an agent with `mm init`](../docs/en/how-to/create-an-agent.md)). | ||
| 103 | - | ||
| 104 | -| Key | What it does | | ||
| 105 | -|---|---| | ||
| 106 | -| `↑` `↓` `Home` `End` | Move through the choices; the preview on the right follows the highlighted one. | | ||
| 107 | -| `Enter` | Answer and go to the next question; on the last screen, write the file. | | ||
| 108 | -| `y` `n` | Answer the yes-or-no question. | | ||
| 109 | -| `Esc` | Go back one question, taking its answer back. | | ||
| 110 | -| `PgUp` `PgDn` | Scroll the preview. | | ||
| 111 | -| `Tab` | On a screen narrower than 100 columns: show the preview in place of the question, and back. | | ||
| 112 | -| `←` `→` | In a text answer (the endpoint, the key's variable, the name, the file): move the cursor; typing inserts there. `Home` `End` (or `Ctrl-A` `Ctrl-E`) go to the start and the end; `Backspace` deletes before the cursor, `Delete` after it. | | ||
| 113 | -| `Ctrl-U` | Clear a text answer. | | ||
| 114 | -| `Ctrl-C` | Quit without writing anything. | | ||
| 115 | - | ||
| 116 | -## Good to know | ||
| 117 | - | ||
| 118 | -- **Keys depend on the terminal.** `Alt-Enter`, `Home`, `End` and the function keys depend on how the terminal reports them; on a Mac laptop, `Fn` is often needed for `F1`, `F2`, `Home` and `End`. `Ctrl-J` always works for a new line. | ||
| 119 | -- **The window needs a real terminal.** `mm -tui | tee log.txt`, or any run where the input or the output is not a terminal, falls back to the line mode, where none of these keys apply. | ||
| 120 | - | ||
| 121 | -See also: [How to use the window mode](../docs/en/how-to/use-the-window-mode.md), [Slash commands and keys (reference)](../docs/en/reference/slash-commands.md). | ||
added
local-ci-0-common.sh +65 -0 | new file mode 100755 | ||
| @@ -0,0 +1,65 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# local-ci-0-common.sh — what the local-ci-*.sh steps share. Sourced, not run. | |
| 3 | +# | |
| 4 | +# The steps, in order: | |
| 5 | +# ./local-ci-1-check.sh gofmt, vet, tests | |
| 6 | +# ./local-ci-2-build.sh the binaries, in release/<TAG>/ | |
| 7 | +# ./local-ci-3-create-draft.sh the tag and a draft prerelease | |
| 8 | +# ./local-ci-4-upload.sh the binaries, through a temporary branch | |
| 9 | +# ./local-ci-5-publish.sh the draft becomes public; asks first | |
| 10 | +# | |
| 11 | +# Tests only: ./local-ci-9-remove-test-release.sh | |
| 12 | +# | |
| 13 | +# Reads TAG, ABOUT, OWNER and REPO from .release.env, and CI_TOKEN from | |
| 14 | +# .ci.cd.token.env. The token never reaches argv: curl and git read it from | |
| 15 | +# files of mode 600 in a temporary folder. | |
| 16 | +set -euo pipefail | |
| 17 | +cd "$(dirname "${BASH_SOURCE[0]}")" | |
| 18 | + | |
| 19 | +# shellcheck disable=SC1090 | |
| 20 | +source "${LOCAL_CI_ENV_FILE:-./.release.env}" | |
| 21 | +: "${TAG:?TAG is not set in .release.env}" | |
| 22 | +OWNER="${OWNER:-bots-garden}" | |
| 23 | +REPO="${REPO:-mini-me}" | |
| 24 | + | |
| 25 | +handle="${RICKUB_HANDLE:-k33g}" | |
| 26 | +web="https://rickub.com/${OWNER}/${REPO}" | |
| 27 | +api="https://rickub.com/api/v1/repos/${OWNER}/${REPO}" | |
| 28 | +git_url="https://${handle}@git.rickub.com/${OWNER}/${REPO}.git" | |
| 29 | +assets_dir="release/${TAG}" | |
| 30 | + | |
| 31 | +work="$(mktemp -d)" | |
| 32 | +cleanup_work() { rm -rf "${work}"; } | |
| 33 | +trap cleanup_work EXIT | |
| 34 | + | |
| 35 | +# load_token prepares the token for curl and git. | |
| 36 | +load_token() { | |
| 37 | + # shellcheck disable=SC1091 | |
| 38 | + source ./.ci.cd.token.env | |
| 39 | + [ -n "${CI_TOKEN:-}" ] || { echo "❌ CI_TOKEN is not set in .ci.cd.token.env"; exit 2; } | |
| 40 | + export CI_TOKEN | |
| 41 | + ( umask 077; printf 'header = "Authorization: Bearer %s"\n' "${CI_TOKEN}" > "${work}/curl.conf" ) | |
| 42 | + ( umask 077; printf '#!/bin/sh\nprintf "%%s" "$CI_TOKEN"\n' > "${work}/askpass.sh" ) | |
| 43 | + chmod 700 "${work}/askpass.sh" | |
| 44 | + export GIT_ASKPASS="${work}/askpass.sh" GIT_TERMINAL_PROMPT=0 | |
| 45 | +} | |
| 46 | + | |
| 47 | +# call METHOD PATH [curl args]: the body lands in ${work}/body, the status is printed. | |
| 48 | +call() { | |
| 49 | + local method="$1" path="$2" | |
| 50 | + shift 2 | |
| 51 | + curl -sS -m 60 -o "${work}/body" -w '%{http_code}' -K "${work}/curl.conf" -X "${method}" "$@" "${api}${path}" | |
| 52 | +} | |
| 53 | + | |
| 54 | +# release_field FIELD prints a field of the release of TAG, or nothing. | |
| 55 | +release_field() { | |
| 56 | + local status | |
| 57 | + status="$(call GET /releases)" | |
| 58 | + [ "${status}" = "200" ] || { echo "❌ HTTP ${status} listing the releases: $(cat "${work}/body")" >&2; exit 1; } | |
| 59 | + jq -r --arg tag "${TAG}" --arg field "$1" '[.[] | select(.tag == $tag)][0][$field] // empty | tostring' "${work}/body" | |
| 60 | +} | |
| 61 | + | |
| 62 | +# latest_location prints where /releases/latest redirects to. | |
| 63 | +latest_location() { | |
| 64 | + curl -sI -m 20 "${web}/releases/latest" | tr -d '\r' | awk 'tolower($1) == "location:" {print $2}' | |
| 65 | +} | |
| new file mode 100755 | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# local-ci-0-common.sh — what the local-ci-*.sh steps share. Sourced, not run. | ||
| 3 | +# | ||
| 4 | +# The steps, in order: | ||
| 5 | +# ./local-ci-1-check.sh gofmt, vet, tests | ||
| 6 | +# ./local-ci-2-build.sh the binaries, in release/<TAG>/ | ||
| 7 | +# ./local-ci-3-create-draft.sh the tag and a draft prerelease | ||
| 8 | +# ./local-ci-4-upload.sh the binaries, through a temporary branch | ||
| 9 | +# ./local-ci-5-publish.sh the draft becomes public; asks first | ||
| 10 | +# | ||
| 11 | +# Tests only: ./local-ci-9-remove-test-release.sh | ||
| 12 | +# | ||
| 13 | +# Reads TAG, ABOUT, OWNER and REPO from .release.env, and CI_TOKEN from | ||
| 14 | +# .ci.cd.token.env. The token never reaches argv: curl and git read it from | ||
| 15 | +# files of mode 600 in a temporary folder. | ||
| 16 | +set -euo pipefail | ||
| 17 | +cd "$(dirname "${BASH_SOURCE[0]}")" | ||
| 18 | + | ||
| 19 | +# shellcheck disable=SC1090 | ||
| 20 | +source "${LOCAL_CI_ENV_FILE:-./.release.env}" | ||
| 21 | +: "${TAG:?TAG is not set in .release.env}" | ||
| 22 | +OWNER="${OWNER:-bots-garden}" | ||
| 23 | +REPO="${REPO:-mini-me}" | ||
| 24 | + | ||
| 25 | +handle="${RICKUB_HANDLE:-k33g}" | ||
| 26 | +web="https://rickub.com/${OWNER}/${REPO}" | ||
| 27 | +api="https://rickub.com/api/v1/repos/${OWNER}/${REPO}" | ||
| 28 | +git_url="https://${handle}@git.rickub.com/${OWNER}/${REPO}.git" | ||
| 29 | +assets_dir="release/${TAG}" | ||
| 30 | + | ||
| 31 | +work="$(mktemp -d)" | ||
| 32 | +cleanup_work() { rm -rf "${work}"; } | ||
| 33 | +trap cleanup_work EXIT | ||
| 34 | + | ||
| 35 | +# load_token prepares the token for curl and git. | ||
| 36 | +load_token() { | ||
| 37 | + # shellcheck disable=SC1091 | ||
| 38 | + source ./.ci.cd.token.env | ||
| 39 | + [ -n "${CI_TOKEN:-}" ] || { echo "❌ CI_TOKEN is not set in .ci.cd.token.env"; exit 2; } | ||
| 40 | + export CI_TOKEN | ||
| 41 | + ( umask 077; printf 'header = "Authorization: Bearer %s"\n' "${CI_TOKEN}" > "${work}/curl.conf" ) | ||
| 42 | + ( umask 077; printf '#!/bin/sh\nprintf "%%s" "$CI_TOKEN"\n' > "${work}/askpass.sh" ) | ||
| 43 | + chmod 700 "${work}/askpass.sh" | ||
| 44 | + export GIT_ASKPASS="${work}/askpass.sh" GIT_TERMINAL_PROMPT=0 | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +# call METHOD PATH [curl args]: the body lands in ${work}/body, the status is printed. | ||
| 48 | +call() { | ||
| 49 | + local method="$1" path="$2" | ||
| 50 | + shift 2 | ||
| 51 | + curl -sS -m 60 -o "${work}/body" -w '%{http_code}' -K "${work}/curl.conf" -X "${method}" "$@" "${api}${path}" | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +# release_field FIELD prints a field of the release of TAG, or nothing. | ||
| 55 | +release_field() { | ||
| 56 | + local status | ||
| 57 | + status="$(call GET /releases)" | ||
| 58 | + [ "${status}" = "200" ] || { echo "❌ HTTP ${status} listing the releases: $(cat "${work}/body")" >&2; exit 1; } | ||
| 59 | + jq -r --arg tag "${TAG}" --arg field "$1" '[.[] | select(.tag == $tag)][0][$field] // empty | tostring' "${work}/body" | ||
| 60 | +} | ||
| 61 | + | ||
| 62 | +# latest_location prints where /releases/latest redirects to. | ||
| 63 | +latest_location() { | ||
| 64 | + curl -sI -m 20 "${web}/releases/latest" | tr -d '\r' | awk 'tolower($1) == "location:" {print $2}' | ||
| 65 | +} | ||
added
local-ci-1-check.sh +19 -0 | new file mode 100755 | ||
| @@ -0,0 +1,19 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# local-ci-1-check.sh — gofmt, vet and tests. | |
| 3 | +source "$(dirname "$0")/local-ci-0-common.sh" | |
| 4 | + | |
| 5 | +echo "==> gofmt" | |
| 6 | +unformatted="$(git ls-files '*.go' | xargs gofmt -l)" | |
| 7 | +if [ -n "${unformatted}" ]; then | |
| 8 | + echo "❌ not formatted:" | |
| 9 | + echo "${unformatted}" | |
| 10 | + exit 1 | |
| 11 | +fi | |
| 12 | + | |
| 13 | +echo "==> go vet" | |
| 14 | +go vet ./... | |
| 15 | + | |
| 16 | +echo "==> go test" | |
| 17 | +go test ./... -count=1 | |
| 18 | + | |
| 19 | +echo "✅ checks passed" | |
| new file mode 100755 | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# local-ci-1-check.sh — gofmt, vet and tests. | ||
| 3 | +source "$(dirname "$0")/local-ci-0-common.sh" | ||
| 4 | + | ||
| 5 | +echo "==> gofmt" | ||
| 6 | +unformatted="$(git ls-files '*.go' | xargs gofmt -l)" | ||
| 7 | +if [ -n "${unformatted}" ]; then | ||
| 8 | + echo "❌ not formatted:" | ||
| 9 | + echo "${unformatted}" | ||
| 10 | + exit 1 | ||
| 11 | +fi | ||
| 12 | + | ||
| 13 | +echo "==> go vet" | ||
| 14 | +go vet ./... | ||
| 15 | + | ||
| 16 | +echo "==> go test" | ||
| 17 | +go test ./... -count=1 | ||
| 18 | + | ||
| 19 | +echo "✅ checks passed" | ||
added
local-ci-2-build.sh +6 -0 | new file mode 100755 | ||
| @@ -0,0 +1,6 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# local-ci-2-build.sh — the binaries for every platform, in release/<TAG>/. | |
| 3 | +source "$(dirname "$0")/local-ci-0-common.sh" | |
| 4 | + | |
| 5 | +bash ./02-build-releases.sh "${TAG}" | |
| 6 | +echo "✅ ${assets_dir}/ is ready" | |
| new file mode 100755 | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# local-ci-2-build.sh — the binaries for every platform, in release/<TAG>/. | ||
| 3 | +source "$(dirname "$0")/local-ci-0-common.sh" | ||
| 4 | + | ||
| 5 | +bash ./02-build-releases.sh "${TAG}" | ||
| 6 | +echo "✅ ${assets_dir}/ is ready" | ||
added
local-ci-3-create-draft.sh +56 -0 | new file mode 100755 | ||
| @@ -0,0 +1,56 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# local-ci-3-create-draft.sh — the tag and a draft prerelease on Rickub. | |
| 3 | +# | |
| 4 | +# Refuses when the binaries would not be what the tag names: the working tree | |
| 5 | +# must be clean and HEAD must be on the remote's main. | |
| 6 | +source "$(dirname "$0")/local-ci-0-common.sh" | |
| 7 | +load_token | |
| 8 | + | |
| 9 | +[ -f "${assets_dir}/SHA256SUMS" ] || { echo "❌ no ${assets_dir}/SHA256SUMS: run local-ci-2-build.sh"; exit 2; } | |
| 10 | + | |
| 11 | +head_sha="$(git rev-parse HEAD)" | |
| 12 | +if [ -z "${LOCAL_CI_SKIP_GIT_CHECK:-}" ]; then | |
| 13 | + if [ -n "$(git status --porcelain)" ]; then | |
| 14 | + echo "❌ the working tree is not clean: commit first" | |
| 15 | + git status --short | |
| 16 | + exit 1 | |
| 17 | + fi | |
| 18 | + remote_main="$(git ls-remote "${git_url}" refs/heads/main | cut -f1)" | |
| 19 | + if [ "${head_sha}" != "${remote_main}" ]; then | |
| 20 | + echo "❌ HEAD (${head_sha}) is not the remote's main (${remote_main}): push first" | |
| 21 | + exit 1 | |
| 22 | + fi | |
| 23 | +fi | |
| 24 | + | |
| 25 | +# With the old workflow on that commit, a v* tag would also start a CI release | |
| 26 | +# that publishes on its own. | |
| 27 | +case "${TAG}" in | |
| 28 | + v*) | |
| 29 | + if [ -n "$(git ls-tree "${head_sha}" .github/workflows)" ]; then | |
| 30 | + echo "❌ ${head_sha} still has .github/workflows: a tag there would start the old Release workflow. Push the commit that renames it." | |
| 31 | + exit 1 | |
| 32 | + fi | |
| 33 | + ;; | |
| 34 | +esac | |
| 35 | + | |
| 36 | +notes_file="release-notes/${TAG}.en.md" | |
| 37 | +{ | |
| 38 | + if [ -f "${notes_file}" ]; then | |
| 39 | + cat "${notes_file}" | |
| 40 | + else | |
| 41 | + printf 'Mini Me %s\n' "${TAG}" | |
| 42 | + fi | |
| 43 | + printf '\n- Commit: `%s`\n- Built on a local machine with %s\n\n## Checksums\n\n```\n' "${head_sha}" "$(go env GOVERSION)" | |
| 44 | + cat "${assets_dir}/SHA256SUMS" | |
| 45 | + printf '```\n' | |
| 46 | +} > "${work}/notes.md" | |
| 47 | + | |
| 48 | +echo "==> creating the draft prerelease ${TAG} on ${head_sha}" | |
| 49 | +payload="$(jq -n --arg tag "${TAG}" --arg target "${head_sha}" --rawfile body "${work}/notes.md" \ | |
| 50 | + '{tag: $tag, title: $tag, target: $target, body: $body, prerelease: true, draft: true}')" | |
| 51 | +status="$(call POST /releases -H 'Content-Type: application/json' -d "${payload}")" | |
| 52 | +case "${status}" in | |
| 53 | + 201) echo "✅ draft ${TAG} created" ;; | |
| 54 | + 409) echo "❌ the release ${TAG} already exists"; exit 1 ;; | |
| 55 | + *) echo "❌ HTTP ${status}: $(cat "${work}/body")"; exit 1 ;; | |
| 56 | +esac | |
| new file mode 100755 | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# local-ci-3-create-draft.sh — the tag and a draft prerelease on Rickub. | ||
| 3 | +# | ||
| 4 | +# Refuses when the binaries would not be what the tag names: the working tree | ||
| 5 | +# must be clean and HEAD must be on the remote's main. | ||
| 6 | +source "$(dirname "$0")/local-ci-0-common.sh" | ||
| 7 | +load_token | ||
| 8 | + | ||
| 9 | +[ -f "${assets_dir}/SHA256SUMS" ] || { echo "❌ no ${assets_dir}/SHA256SUMS: run local-ci-2-build.sh"; exit 2; } | ||
| 10 | + | ||
| 11 | +head_sha="$(git rev-parse HEAD)" | ||
| 12 | +if [ -z "${LOCAL_CI_SKIP_GIT_CHECK:-}" ]; then | ||
| 13 | + if [ -n "$(git status --porcelain)" ]; then | ||
| 14 | + echo "❌ the working tree is not clean: commit first" | ||
| 15 | + git status --short | ||
| 16 | + exit 1 | ||
| 17 | + fi | ||
| 18 | + remote_main="$(git ls-remote "${git_url}" refs/heads/main | cut -f1)" | ||
| 19 | + if [ "${head_sha}" != "${remote_main}" ]; then | ||
| 20 | + echo "❌ HEAD (${head_sha}) is not the remote's main (${remote_main}): push first" | ||
| 21 | + exit 1 | ||
| 22 | + fi | ||
| 23 | +fi | ||
| 24 | + | ||
| 25 | +# With the old workflow on that commit, a v* tag would also start a CI release | ||
| 26 | +# that publishes on its own. | ||
| 27 | +case "${TAG}" in | ||
| 28 | + v*) | ||
| 29 | + if [ -n "$(git ls-tree "${head_sha}" .github/workflows)" ]; then | ||
| 30 | + echo "❌ ${head_sha} still has .github/workflows: a tag there would start the old Release workflow. Push the commit that renames it." | ||
| 31 | + exit 1 | ||
| 32 | + fi | ||
| 33 | + ;; | ||
| 34 | +esac | ||
| 35 | + | ||
| 36 | +notes_file="release-notes/${TAG}.en.md" | ||
| 37 | +{ | ||
| 38 | + if [ -f "${notes_file}" ]; then | ||
| 39 | + cat "${notes_file}" | ||
| 40 | + else | ||
| 41 | + printf 'Mini Me %s\n' "${TAG}" | ||
| 42 | + fi | ||
| 43 | + printf '\n- Commit: `%s`\n- Built on a local machine with %s\n\n## Checksums\n\n```\n' "${head_sha}" "$(go env GOVERSION)" | ||
| 44 | + cat "${assets_dir}/SHA256SUMS" | ||
| 45 | + printf '```\n' | ||
| 46 | +} > "${work}/notes.md" | ||
| 47 | + | ||
| 48 | +echo "==> creating the draft prerelease ${TAG} on ${head_sha}" | ||
| 49 | +payload="$(jq -n --arg tag "${TAG}" --arg target "${head_sha}" --rawfile body "${work}/notes.md" \ | ||
| 50 | + '{tag: $tag, title: $tag, target: $target, body: $body, prerelease: true, draft: true}')" | ||
| 51 | +status="$(call POST /releases -H 'Content-Type: application/json' -d "${payload}")" | ||
| 52 | +case "${status}" in | ||
| 53 | + 201) echo "✅ draft ${TAG} created" ;; | ||
| 54 | + 409) echo "❌ the release ${TAG} already exists"; exit 1 ;; | ||
| 55 | + *) echo "❌ HTTP ${status}: $(cat "${work}/body")"; exit 1 ;; | ||
| 56 | +esac | ||
added
local-ci-4-upload.sh +108 -0 | new file mode 100755 | ||
| @@ -0,0 +1,108 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# local-ci-4-upload.sh — the binaries of release/<TAG>/ onto the draft. | |
| 3 | +# | |
| 4 | +# Rickub only accepts uploads from the token of a CI job. So this pushes a | |
| 5 | +# temporary orphan branch holding the binaries and a one-job workflow, waits for | |
| 6 | +# the job, and deletes the branch, whatever happened. The local checkout is | |
| 7 | +# never touched. | |
| 8 | +source "$(dirname "$0")/local-ci-0-common.sh" | |
| 9 | +load_token | |
| 10 | + | |
| 11 | +branch="local-ci-publish-${TAG}" | |
| 12 | +run_timeout_seconds=900 | |
| 13 | +branch_pushed="" | |
| 14 | + | |
| 15 | +remove_branch() { | |
| 16 | + if [ -n "${branch_pushed}" ]; then | |
| 17 | + echo "==> deleting the branch ${branch}" | |
| 18 | + git -C "${work}/branch" push -q "${git_url}" --delete "${branch}" \ | |
| 19 | + || echo "⚠️ could not delete ${branch}: delete it by hand" | |
| 20 | + fi | |
| 21 | + cleanup_work | |
| 22 | +} | |
| 23 | +trap remove_branch EXIT | |
| 24 | + | |
| 25 | +[ -f "${assets_dir}/SHA256SUMS" ] || { echo "❌ no ${assets_dir}/SHA256SUMS: run local-ci-2-build.sh"; exit 2; } | |
| 26 | +[ "$(release_field draft)" = "true" ] || { echo "❌ ${TAG} is not a draft: run local-ci-3-create-draft.sh"; exit 1; } | |
| 27 | + | |
| 28 | +echo "==> preparing the temporary branch" | |
| 29 | +git init -q -b "${branch}" "${work}/branch" | |
| 30 | +mkdir -p "${work}/branch/assets" "${work}/branch/.github/workflows" | |
| 31 | +cp "${assets_dir}"/mm-* "${assets_dir}/SHA256SUMS" "${work}/branch/assets/" | |
| 32 | +printf '%s\n' "${TAG}" > "${work}/branch/TAG" | |
| 33 | +cat > "${work}/branch/.github/workflows/local-ci-publish.yml" <<'WORKFLOW' | |
| 34 | +name: local ci publish | |
| 35 | +on: | |
| 36 | + push: | |
| 37 | + branches: | |
| 38 | + - "local-ci-publish-*" | |
| 39 | +permissions: | |
| 40 | + contents: write | |
| 41 | +jobs: | |
| 42 | + upload: | |
| 43 | + runs-on: ubuntu-latest | |
| 44 | + steps: | |
| 45 | + - uses: actions/checkout@v4 | |
| 46 | + - name: Upload the binaries to the release | |
| 47 | + env: | |
| 48 | + GITHUB_TOKEN: ${{ github.token }} | |
| 49 | + run: bash ./upload.sh | |
| 50 | +WORKFLOW | |
| 51 | +cat > "${work}/branch/upload.sh" <<'UPLOAD' | |
| 52 | +#!/usr/bin/env bash | |
| 53 | +set -euo pipefail | |
| 54 | +tag="$(cat TAG)" | |
| 55 | +api="${GITHUB_API_URL%/}/repos/${GITHUB_REPOSITORY}" | |
| 56 | +config="$(mktemp)" | |
| 57 | +printf 'header = "Authorization: Bearer %s"\n' "${GITHUB_TOKEN}" > "${config}" | |
| 58 | +curl -fsS -K "${config}" "${api}/releases?per_page=100" > releases.json | |
| 59 | +upload_url="$(jq -r --arg tag "${tag}" '[.[] | select(.tag_name == $tag)][0].upload_url // empty' releases.json | sed 's/{[^}]*}$//')" | |
| 60 | +[ -n "${upload_url}" ] || { echo "::error::no release ${tag} visible to the job"; exit 1; } | |
| 61 | +for file in assets/*; do | |
| 62 | + name="$(basename "${file}")" | |
| 63 | + status="$(curl -sS -o response.json -w '%{http_code}' -K "${config}" -X POST \ | |
| 64 | + -H 'Content-Type: application/octet-stream' --data-binary @"${file}" "${upload_url}?name=${name}")" | |
| 65 | + [ "${status}" = "201" ] || { echo "::error::HTTP ${status} uploading ${name}: $(cat response.json)"; exit 1; } | |
| 66 | + echo "uploaded ${name}" | |
| 67 | +done | |
| 68 | +release_id="$(jq -r --arg tag "${tag}" '[.[] | select(.tag_name == $tag)][0].id' releases.json)" | |
| 69 | +curl -fsS -K "${config}" "${api}/releases/${release_id}/assets" | jq -r '.[] | "asset \(.name) \(.size)"' | |
| 70 | +UPLOAD | |
| 71 | +git -C "${work}/branch" add -A | |
| 72 | +git -C "${work}/branch" -c user.name="${handle}" -c user.email="${handle}@users.noreply.rickub.com" commit -q -m "local ci: temporary branch to publish ${TAG}" | |
| 73 | +head_sha="$(git -C "${work}/branch" rev-parse HEAD)" | |
| 74 | +echo " $(du -sh "${work}/branch/assets" | cut -f1) of binaries" | |
| 75 | + | |
| 76 | +echo "==> pushing ${branch}" | |
| 77 | +git -C "${work}/branch" push -q "${git_url}" "HEAD:refs/heads/${branch}" | |
| 78 | +branch_pushed="yes" | |
| 79 | + | |
| 80 | +echo "==> waiting for the CI job" | |
| 81 | +deadline=$(( SECONDS + run_timeout_seconds )) | |
| 82 | +run_number="" | |
| 83 | +run_status="" | |
| 84 | +while [ "${SECONDS}" -lt "${deadline}" ]; do | |
| 85 | + sleep 10 | |
| 86 | + status="$(call GET /actions/runs)" | |
| 87 | + [ "${status}" = "200" ] || continue | |
| 88 | + run="$(jq -c --arg sha "${head_sha}" '[.items[] | select(.head_sha == $sha)][0] // empty' "${work}/body")" | |
| 89 | + [ -n "${run}" ] || continue | |
| 90 | + run_number="$(jq -r '.number' <<<"${run}")" | |
| 91 | + run_status="$(jq -r '.status' <<<"${run}")" | |
| 92 | + echo " run ${run_number}: ${run_status}" | |
| 93 | + case "${run_status}" in | |
| 94 | + queued | pending | running | in_progress | waiting) ;; | |
| 95 | + *) break ;; | |
| 96 | + esac | |
| 97 | +done | |
| 98 | + | |
| 99 | +if [ -n "${run_number}" ] && [ "$(call GET "/actions/runs/${run_number}/logs")" = "200" ]; then | |
| 100 | + jq -r '.jobs[].log // empty' "${work}/body" > "${work}/run.log" | |
| 101 | + grep -E '(^| )(uploaded |asset |::error::)' "${work}/run.log" | cut -c1-160 || true | |
| 102 | +fi | |
| 103 | +[ "${run_status}" = "success" ] || { echo "❌ the job did not succeed (run ${run_number:-none}: ${run_status:-no run seen})"; exit 1; } | |
| 104 | + | |
| 105 | +expected="$(find "${work}/branch/assets" -type f | wc -l | tr -d ' ')" | |
| 106 | +uploaded="$(grep -cE '(^| )asset ' "${work}/run.log" || true)" | |
| 107 | +[ "${uploaded}" = "${expected}" ] || { echo "❌ ${uploaded} assets on the release, ${expected} expected"; exit 1; } | |
| 108 | +echo "✅ ${expected} files on the draft ${TAG}" | |
| new file mode 100755 | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# local-ci-4-upload.sh — the binaries of release/<TAG>/ onto the draft. | ||
| 3 | +# | ||
| 4 | +# Rickub only accepts uploads from the token of a CI job. So this pushes a | ||
| 5 | +# temporary orphan branch holding the binaries and a one-job workflow, waits for | ||
| 6 | +# the job, and deletes the branch, whatever happened. The local checkout is | ||
| 7 | +# never touched. | ||
| 8 | +source "$(dirname "$0")/local-ci-0-common.sh" | ||
| 9 | +load_token | ||
| 10 | + | ||
| 11 | +branch="local-ci-publish-${TAG}" | ||
| 12 | +run_timeout_seconds=900 | ||
| 13 | +branch_pushed="" | ||
| 14 | + | ||
| 15 | +remove_branch() { | ||
| 16 | + if [ -n "${branch_pushed}" ]; then | ||
| 17 | + echo "==> deleting the branch ${branch}" | ||
| 18 | + git -C "${work}/branch" push -q "${git_url}" --delete "${branch}" \ | ||
| 19 | + || echo "⚠️ could not delete ${branch}: delete it by hand" | ||
| 20 | + fi | ||
| 21 | + cleanup_work | ||
| 22 | +} | ||
| 23 | +trap remove_branch EXIT | ||
| 24 | + | ||
| 25 | +[ -f "${assets_dir}/SHA256SUMS" ] || { echo "❌ no ${assets_dir}/SHA256SUMS: run local-ci-2-build.sh"; exit 2; } | ||
| 26 | +[ "$(release_field draft)" = "true" ] || { echo "❌ ${TAG} is not a draft: run local-ci-3-create-draft.sh"; exit 1; } | ||
| 27 | + | ||
| 28 | +echo "==> preparing the temporary branch" | ||
| 29 | +git init -q -b "${branch}" "${work}/branch" | ||
| 30 | +mkdir -p "${work}/branch/assets" "${work}/branch/.github/workflows" | ||
| 31 | +cp "${assets_dir}"/mm-* "${assets_dir}/SHA256SUMS" "${work}/branch/assets/" | ||
| 32 | +printf '%s\n' "${TAG}" > "${work}/branch/TAG" | ||
| 33 | +cat > "${work}/branch/.github/workflows/local-ci-publish.yml" <<'WORKFLOW' | ||
| 34 | +name: local ci publish | ||
| 35 | +on: | ||
| 36 | + push: | ||
| 37 | + branches: | ||
| 38 | + - "local-ci-publish-*" | ||
| 39 | +permissions: | ||
| 40 | + contents: write | ||
| 41 | +jobs: | ||
| 42 | + upload: | ||
| 43 | + runs-on: ubuntu-latest | ||
| 44 | + steps: | ||
| 45 | + - uses: actions/checkout@v4 | ||
| 46 | + - name: Upload the binaries to the release | ||
| 47 | + env: | ||
| 48 | + GITHUB_TOKEN: ${{ github.token }} | ||
| 49 | + run: bash ./upload.sh | ||
| 50 | +WORKFLOW | ||
| 51 | +cat > "${work}/branch/upload.sh" <<'UPLOAD' | ||
| 52 | +#!/usr/bin/env bash | ||
| 53 | +set -euo pipefail | ||
| 54 | +tag="$(cat TAG)" | ||
| 55 | +api="${GITHUB_API_URL%/}/repos/${GITHUB_REPOSITORY}" | ||
| 56 | +config="$(mktemp)" | ||
| 57 | +printf 'header = "Authorization: Bearer %s"\n' "${GITHUB_TOKEN}" > "${config}" | ||
| 58 | +curl -fsS -K "${config}" "${api}/releases?per_page=100" > releases.json | ||
| 59 | +upload_url="$(jq -r --arg tag "${tag}" '[.[] | select(.tag_name == $tag)][0].upload_url // empty' releases.json | sed 's/{[^}]*}$//')" | ||
| 60 | +[ -n "${upload_url}" ] || { echo "::error::no release ${tag} visible to the job"; exit 1; } | ||
| 61 | +for file in assets/*; do | ||
| 62 | + name="$(basename "${file}")" | ||
| 63 | + status="$(curl -sS -o response.json -w '%{http_code}' -K "${config}" -X POST \ | ||
| 64 | + -H 'Content-Type: application/octet-stream' --data-binary @"${file}" "${upload_url}?name=${name}")" | ||
| 65 | + [ "${status}" = "201" ] || { echo "::error::HTTP ${status} uploading ${name}: $(cat response.json)"; exit 1; } | ||
| 66 | + echo "uploaded ${name}" | ||
| 67 | +done | ||
| 68 | +release_id="$(jq -r --arg tag "${tag}" '[.[] | select(.tag_name == $tag)][0].id' releases.json)" | ||
| 69 | +curl -fsS -K "${config}" "${api}/releases/${release_id}/assets" | jq -r '.[] | "asset \(.name) \(.size)"' | ||
| 70 | +UPLOAD | ||
| 71 | +git -C "${work}/branch" add -A | ||
| 72 | +git -C "${work}/branch" -c user.name="${handle}" -c user.email="${handle}@users.noreply.rickub.com" commit -q -m "local ci: temporary branch to publish ${TAG}" | ||
| 73 | +head_sha="$(git -C "${work}/branch" rev-parse HEAD)" | ||
| 74 | +echo " $(du -sh "${work}/branch/assets" | cut -f1) of binaries" | ||
| 75 | + | ||
| 76 | +echo "==> pushing ${branch}" | ||
| 77 | +git -C "${work}/branch" push -q "${git_url}" "HEAD:refs/heads/${branch}" | ||
| 78 | +branch_pushed="yes" | ||
| 79 | + | ||
| 80 | +echo "==> waiting for the CI job" | ||
| 81 | +deadline=$(( SECONDS + run_timeout_seconds )) | ||
| 82 | +run_number="" | ||
| 83 | +run_status="" | ||
| 84 | +while [ "${SECONDS}" -lt "${deadline}" ]; do | ||
| 85 | + sleep 10 | ||
| 86 | + status="$(call GET /actions/runs)" | ||
| 87 | + [ "${status}" = "200" ] || continue | ||
| 88 | + run="$(jq -c --arg sha "${head_sha}" '[.items[] | select(.head_sha == $sha)][0] // empty' "${work}/body")" | ||
| 89 | + [ -n "${run}" ] || continue | ||
| 90 | + run_number="$(jq -r '.number' <<<"${run}")" | ||
| 91 | + run_status="$(jq -r '.status' <<<"${run}")" | ||
| 92 | + echo " run ${run_number}: ${run_status}" | ||
| 93 | + case "${run_status}" in | ||
| 94 | + queued | pending | running | in_progress | waiting) ;; | ||
| 95 | + *) break ;; | ||
| 96 | + esac | ||
| 97 | +done | ||
| 98 | + | ||
| 99 | +if [ -n "${run_number}" ] && [ "$(call GET "/actions/runs/${run_number}/logs")" = "200" ]; then | ||
| 100 | + jq -r '.jobs[].log // empty' "${work}/body" > "${work}/run.log" | ||
| 101 | + grep -E '(^| )(uploaded |asset |::error::)' "${work}/run.log" | cut -c1-160 || true | ||
| 102 | +fi | ||
| 103 | +[ "${run_status}" = "success" ] || { echo "❌ the job did not succeed (run ${run_number:-none}: ${run_status:-no run seen})"; exit 1; } | ||
| 104 | + | ||
| 105 | +expected="$(find "${work}/branch/assets" -type f | wc -l | tr -d ' ')" | ||
| 106 | +uploaded="$(grep -cE '(^| )asset ' "${work}/run.log" || true)" | ||
| 107 | +[ "${uploaded}" = "${expected}" ] || { echo "❌ ${uploaded} assets on the release, ${expected} expected"; exit 1; } | ||
| 108 | +echo "✅ ${expected} files on the draft ${TAG}" | ||
added
local-ci-5-publish.sh +40 -0 | new file mode 100755 | ||
| @@ -0,0 +1,40 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# local-ci-5-publish.sh — the draft becomes public, as a prerelease. | |
| 3 | +# | |
| 4 | +# On Rickub a published prerelease becomes /releases/latest, so everybody who | |
| 5 | +# downloads the latest version gets this one. It asks you to type the tag first, | |
| 6 | +# then downloads what is public and compares it with release/<TAG>/. | |
| 7 | +source "$(dirname "$0")/local-ci-0-common.sh" | |
| 8 | +load_token | |
| 9 | + | |
| 10 | +[ -f "${assets_dir}/SHA256SUMS" ] || { echo "❌ no ${assets_dir}/SHA256SUMS: run local-ci-2-build.sh"; exit 2; } | |
| 11 | +id="$(release_field id)" | |
| 12 | +[ -n "${id}" ] || { echo "❌ no release ${TAG}: run local-ci-3-create-draft.sh"; exit 1; } | |
| 13 | +[ "$(release_field draft)" = "true" ] || { echo "❌ ${TAG} is already public"; exit 1; } | |
| 14 | + | |
| 15 | +echo "/releases/latest is now: $(latest_location)" | |
| 16 | +echo "Publishing makes ${TAG} the latest version for everybody." | |
| 17 | +printf 'Type %s to publish: ' "${TAG}" | |
| 18 | +read -r answer || answer="" | |
| 19 | +[ "${answer}" = "${TAG}" ] || { echo "❌ not published"; exit 1; } | |
| 20 | + | |
| 21 | +status="$(call PATCH "/releases/${id}" -H 'Content-Type: application/json' -d '{"draft": false, "prerelease": true}')" | |
| 22 | +[ "${status}" = "200" ] || { echo "❌ HTTP ${status}: $(cat "${work}/body")"; exit 1; } | |
| 23 | +echo "==> published" | |
| 24 | + | |
| 25 | +echo "==> checking what is public" | |
| 26 | +mkdir -p "${work}/download" | |
| 27 | +curl -fsSL -m 60 "${web}/releases/download/${TAG}/SHA256SUMS" -o "${work}/download/SHA256SUMS" | |
| 28 | +cmp "${work}/download/SHA256SUMS" "${assets_dir}/SHA256SUMS" || { echo "❌ SHA256SUMS differs"; exit 1; } | |
| 29 | +while read -r _ name; do | |
| 30 | + curl -fsSL -m 300 "${web}/releases/download/${TAG}/${name}" -o "${work}/download/${name}" | |
| 31 | +done < "${assets_dir}/SHA256SUMS" | |
| 32 | +( cd "${work}/download" && sha256sum -c SHA256SUMS ) | |
| 33 | + | |
| 34 | +location="$(latest_location)" | |
| 35 | +echo "/releases/latest -> ${location}" | |
| 36 | +case "${location}" in | |
| 37 | + *"/${TAG}") ;; | |
| 38 | + *) echo "⚠️ /releases/latest does not point at ${TAG}" ;; | |
| 39 | +esac | |
| 40 | +echo "✅ ${TAG} is public" | |
| new file mode 100755 | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# local-ci-5-publish.sh — the draft becomes public, as a prerelease. | ||
| 3 | +# | ||
| 4 | +# On Rickub a published prerelease becomes /releases/latest, so everybody who | ||
| 5 | +# downloads the latest version gets this one. It asks you to type the tag first, | ||
| 6 | +# then downloads what is public and compares it with release/<TAG>/. | ||
| 7 | +source "$(dirname "$0")/local-ci-0-common.sh" | ||
| 8 | +load_token | ||
| 9 | + | ||
| 10 | +[ -f "${assets_dir}/SHA256SUMS" ] || { echo "❌ no ${assets_dir}/SHA256SUMS: run local-ci-2-build.sh"; exit 2; } | ||
| 11 | +id="$(release_field id)" | ||
| 12 | +[ -n "${id}" ] || { echo "❌ no release ${TAG}: run local-ci-3-create-draft.sh"; exit 1; } | ||
| 13 | +[ "$(release_field draft)" = "true" ] || { echo "❌ ${TAG} is already public"; exit 1; } | ||
| 14 | + | ||
| 15 | +echo "/releases/latest is now: $(latest_location)" | ||
| 16 | +echo "Publishing makes ${TAG} the latest version for everybody." | ||
| 17 | +printf 'Type %s to publish: ' "${TAG}" | ||
| 18 | +read -r answer || answer="" | ||
| 19 | +[ "${answer}" = "${TAG}" ] || { echo "❌ not published"; exit 1; } | ||
| 20 | + | ||
| 21 | +status="$(call PATCH "/releases/${id}" -H 'Content-Type: application/json' -d '{"draft": false, "prerelease": true}')" | ||
| 22 | +[ "${status}" = "200" ] || { echo "❌ HTTP ${status}: $(cat "${work}/body")"; exit 1; } | ||
| 23 | +echo "==> published" | ||
| 24 | + | ||
| 25 | +echo "==> checking what is public" | ||
| 26 | +mkdir -p "${work}/download" | ||
| 27 | +curl -fsSL -m 60 "${web}/releases/download/${TAG}/SHA256SUMS" -o "${work}/download/SHA256SUMS" | ||
| 28 | +cmp "${work}/download/SHA256SUMS" "${assets_dir}/SHA256SUMS" || { echo "❌ SHA256SUMS differs"; exit 1; } | ||
| 29 | +while read -r _ name; do | ||
| 30 | + curl -fsSL -m 300 "${web}/releases/download/${TAG}/${name}" -o "${work}/download/${name}" | ||
| 31 | +done < "${assets_dir}/SHA256SUMS" | ||
| 32 | +( cd "${work}/download" && sha256sum -c SHA256SUMS ) | ||
| 33 | + | ||
| 34 | +location="$(latest_location)" | ||
| 35 | +echo "/releases/latest -> ${location}" | ||
| 36 | +case "${location}" in | ||
| 37 | + *"/${TAG}") ;; | ||
| 38 | + *) echo "⚠️ /releases/latest does not point at ${TAG}" ;; | ||
| 39 | +esac | ||
| 40 | +echo "✅ ${TAG} is public" | ||
added
local-ci-9-remove-test-release.sh +26 -0 | new file mode 100755 | ||
| @@ -0,0 +1,26 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# local-ci-9-remove-test-release.sh — delete a test release, for v9.9.9 and | |
| 3 | +# demo-* only: this must never reach a real one. | |
| 4 | +# | |
| 5 | +# ./local-ci-9-remove-test-release.sh # the TAG of .release.env | |
| 6 | +# ./local-ci-9-remove-test-release.sh demo-002 | |
| 7 | +# | |
| 8 | +# The tag stays: Rickub refuses to delete one by push, and the API has no route | |
| 9 | +# for it. Delete it from the repository's Tags page. | |
| 10 | +source "$(dirname "$0")/local-ci-0-common.sh" | |
| 11 | +load_token | |
| 12 | + | |
| 13 | +TAG="${1:-${TAG}}" | |
| 14 | +case "${TAG}" in | |
| 15 | + v9.9.9 | demo-*) ;; | |
| 16 | + *) echo "❌ refusing ${TAG}: only v9.9.9 and demo-*"; exit 2 ;; | |
| 17 | +esac | |
| 18 | + | |
| 19 | +id="$(release_field id)" | |
| 20 | +if [ -n "${id}" ]; then | |
| 21 | + echo "release ${TAG}: HTTP $(call DELETE "/releases/${id}")" | |
| 22 | +else | |
| 23 | + echo "release ${TAG}: none" | |
| 24 | +fi | |
| 25 | +echo "/releases/latest -> $(latest_location)" | |
| 26 | +echo "tag ${TAG}: delete it from the Tags page of ${web}" | |
| new file mode 100755 | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | +#!/usr/bin/env bash | ||
| 2 | +# local-ci-9-remove-test-release.sh — delete a test release, for v9.9.9 and | ||
| 3 | +# demo-* only: this must never reach a real one. | ||
| 4 | +# | ||
| 5 | +# ./local-ci-9-remove-test-release.sh # the TAG of .release.env | ||
| 6 | +# ./local-ci-9-remove-test-release.sh demo-002 | ||
| 7 | +# | ||
| 8 | +# The tag stays: Rickub refuses to delete one by push, and the API has no route | ||
| 9 | +# for it. Delete it from the repository's Tags page. | ||
| 10 | +source "$(dirname "$0")/local-ci-0-common.sh" | ||
| 11 | +load_token | ||
| 12 | + | ||
| 13 | +TAG="${1:-${TAG}}" | ||
| 14 | +case "${TAG}" in | ||
| 15 | + v9.9.9 | demo-*) ;; | ||
| 16 | + *) echo "❌ refusing ${TAG}: only v9.9.9 and demo-*"; exit 2 ;; | ||
| 17 | +esac | ||
| 18 | + | ||
| 19 | +id="$(release_field id)" | ||
| 20 | +if [ -n "${id}" ]; then | ||
| 21 | + echo "release ${TAG}: HTTP $(call DELETE "/releases/${id}")" | ||
| 22 | +else | ||
| 23 | + echo "release ${TAG}: none" | ||
| 24 | +fi | ||
| 25 | +echo "/releases/latest -> $(latest_location)" | ||
| 26 | +echo "tag ${TAG}: delete it from the Tags page of ${web}" | ||