fix(install): make fresh install actually complete + ship tamagotchi
Some checks failed
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / preflight (pull_request) Has been cancelled
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / vps-smoke (pull_request) Has been cancelled
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:frustration-matrix,kei-frustration-loop,kei-skill-importer,kei-projects-index,kei-projects-watcher,kei-gdrive-import,kei-leak-matrix,kei-skills,kei-gateway,kei-cron-scheduler,kei-export-trajectories,kei-backend-daytona,kei-d… (pull_request) Has been cancelled
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:kei-compute-baremetal,kei-compute-vultr,kei-compute-linode,kei-compute-digitalocean,kei-svc-systemd,kei-llm-bridge-mlx name:hosted-sleep-compute]) (pull_request) Has been cancelled
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:kei-diff,kei-scheduler,kei-watch,kei-prune,kei-discover,kei-brain-view,kei-hibernate,kei-ledger-sign,kei-fork name:wave13-15]) (pull_request) Has been cancelled
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:kei-git-gitea,kei-git-forgejo,kei-git-gitlab,kei-git-bitbucket,kei-memory-sled,kei-memory-redis,kei-memory-postgres,kei-memory-sqlite,kei-auth-google,kei-auth-apple,kei-auth-magiclink,kei-auth-webauthn,kei-notify-slack,kei-n… (pull_request) Has been cancelled
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:kei-ledger,kei-migrate,kei-changelog,kei-memory,kei-store,kei-conflict-scan,kei-refactor-engine,kei-graph-check,kei-shared,kei-dna-index,kei-pet name:core]) (pull_request) Has been cancelled
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:kei-machine-probe,kei-llm-ollama,kei-llm-llamacpp,kei-llm-mlx,kei-llm-router,kei-model name:llm-stack]) (pull_request) Has been cancelled
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:kei-router,kei-sage,kei-task,kei-chat-store,kei-crossdomain,kei-search-core,kei-content-store,kei-social-store,kei-curator,kei-auth,kei-artifact name:mcp-lbm]) (pull_request) Has been cancelled
CI (Forgejo Actions — self-hosted runner on Mac, host mode) / rust-primitives (map[crates:keisei,kei-forge,kei-runtime,kei-runtime-core,kei-atom-discovery,kei-agent-runtime,kei-capability,kei-provision,kei-entity-store,kei-pipe,kei-cache,kei-spawn,kei-replay name:atom-substrate]) (pull_request) Has been cancelled

Root causes found by reproducing a clean install from keigit:

1. PROFILE_PRIMS resolved only inside check_prereqs → unbound for
   --no-execute (plan showed 0 prims for every profile) and silently
   empty for --skip-prereqs. Now resolved unconditionally in install.sh
   before any reader (SSoT).

2. Every profile (even minimal, advertised "no Rust compile") fell back
   to a 5-15 min `cargo build --workspace` because no prebuilt release
   binaries exist. Auto-set KEI_SKIP_RUST for profiles with no rust
   primitives → minimal installs in ~18s (assembler only). cargo stays a
   hard prereq because the agent assembler always compiles.

3. The assembler aborted the WHOLE install on any single bad manifest
   (set -e). generate_agents is now tolerant: bad manifests print FAIL
   but hooks/skills/settings still land. Commit-time validate stays strict.

4. Data bugs that broke the assembler:
   - duplicate [taxonomy] table in _roles/{auditor,merger}.toml
   - fal-ai-runner handoff → keimd-expert (not shipped in kit)
   - infra-implementer-cicd forbidden_domain literal `${{ secrets.NAME }}`
     collided with assembler ${{ }} placeholder detection

5. Metadata: KeiSei84 (nonexistent GitHub org) → KeiSeiLab/KeiSeiKit-1.0
   across plugin manifests, bootstrap, README, docs, Cargo/npm metadata.
   .claude-plugin/{plugin,marketplace}.json 0.16.0 → 0.38.0. SECURITY.md
   supported version 0.14.x → 0.38.x.

feat: ship KeiSei tamagotchi statusline into the kit
   - scripts/keisei-pet{,-update}.sh (portable, state under ~/.claude/pet/)
   - install copies them to ~/.claude/scripts/
   - settings-snippet adds statusLine (set-if-absent, never clobbers an
     existing one) + 4 pet-update hooks (prompt/rust_write/github_block/sleep)

Verified: clean minimal install RC=0, zero FAIL, 38 agents + 52 hooks +
68 skills, settings valid, statusLine wired, pet renders, idempotent re-run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
KeiSei84 2026-05-21 00:14:17 +08:00
parent 53ada048b2
commit 98b6f9ab64
28 changed files with 330 additions and 60 deletions

View file

@ -1,21 +1,21 @@
{ {
"name": "keisei-marketplace", "name": "keisei-marketplace",
"owner": { "owner": {
"name": "KeiSei84", "name": "Denis Parfionovich",
"url": "https://github.com/KeiSei84" "url": "https://github.com/KeiSeiLab"
}, },
"metadata": { "metadata": {
"description": "KeiSei Constructor-Pattern kits and primitives for Claude Code", "description": "KeiSei Constructor-Pattern kits and primitives for Claude Code",
"version": "0.16.0" "version": "0.38.0"
}, },
"plugins": [ "plugins": [
{ {
"name": "keisei", "name": "keisei",
"source": { "source": {
"source": "github", "source": "github",
"repo": "KeiSei84/KeiSeiKit" "repo": "KeiSeiLab/KeiSeiKit-1.0"
}, },
"description": "Full KeiSeiKit — 38 agent manifests, 68 skills, 38 hooks, 105 Rust workspace crates (47 installable primitives via MANIFEST.toml `full` profile + 14 shell primitives), sleep-sync cloud consolidation, MCP server layer" "description": "Full KeiSeiKit — agent manifests, skills, hooks, Rust workspace primitives via MANIFEST.toml profiles (classic ./install.sh), sleep-sync cloud consolidation, MCP server layer"
} }
] ]
} }

View file

@ -1,13 +1,13 @@
{ {
"name": "keisei", "name": "keisei",
"version": "0.16.0", "version": "0.38.0",
"description": "Constructor-Pattern agent kit for Claude Code: 38 agent manifests, 68 portable skills, 38 hooks, 105 Rust workspace crates (47 installable primitives + 14 shell primitives via MANIFEST.toml `full` profile), typed artifact handoff, sleep-sync cloud consolidation, MCP server layer.", "description": "Constructor-Pattern agent substrate for Claude Code: agent manifests, portable skills, hooks, Rust workspace primitives (installable via MANIFEST.toml profiles through classic ./install.sh), typed artifact handoff, sleep-sync cloud consolidation, MCP server layer.",
"author": { "author": {
"name": "KeiSei", "name": "Denis Parfionovich",
"url": "https://github.com/KeiSei84" "url": "https://github.com/KeiSeiLab"
}, },
"homepage": "https://github.com/KeiSei84/KeiSeiKit", "homepage": "https://github.com/KeiSeiLab/KeiSeiKit-1.0",
"repository": "https://github.com/KeiSei84/KeiSeiKit", "repository": "https://github.com/KeiSeiLab/KeiSeiKit-1.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"keywords": [ "keywords": [
"constructor-pattern", "constructor-pattern",

View file

@ -383,5 +383,5 @@ Per RULE 0.13 (orchestrator branch first), each phase = orchestrator-created bra
## Sources ## Sources
- `/tmp/hermes-research/hermes-agent/` (NousResearch/hermes-agent @ HEAD, 2026-04-28) - `/tmp/hermes-research/hermes-agent/` (NousResearch/hermes-agent @ HEAD, 2026-04-28)
- `~/Projects/KeiSeiKit/` (local, public mirror github.com/KeiSei84/KeiSeiKit-1.0) - `~/Projects/KeiSeiKit/` (local, public mirror github.com/KeiSeiLab/KeiSeiKit-1.0)
- 7 parallel Explore agents, 2026-04-28 session. - 7 parallel Explore agents, 2026-04-28 session.

View file

@ -6,7 +6,7 @@ This document describes the plugin-format install path (v0.16+) and how it relat
```bash ```bash
# One-time # One-time
/plugin marketplace add KeiSei84/KeiSeiKit /plugin marketplace add KeiSeiLab/KeiSeiKit-1.0
# Install # Install
/plugin install keisei@keisei-marketplace /plugin install keisei@keisei-marketplace
``` ```
@ -50,7 +50,7 @@ Paths inside `hooks/hooks.json` use `${CLAUDE_PLUGIN_ROOT}` (expanded by Claude
**For plugin install:** **For plugin install:**
- Claude Code 2.1+ (check with `claude --version`) - Claude Code 2.1+ (check with `claude --version`)
- Network access to `github.com/KeiSei84/KeiSeiKit` on `/plugin marketplace add` - Network access to `github.com/KeiSeiLab/KeiSeiKit-1.0` on `/plugin marketplace add`
**For the MCP server subset:** **For the MCP server subset:**
- `@keisei/mcp-server` available from **keigit.com** - `@keisei/mcp-server` available from **keigit.com**
@ -76,7 +76,7 @@ Paths inside `hooks/hooks.json` use `${CLAUDE_PLUGIN_ROOT}` (expanded by Claude
## Feedback & bugs ## Feedback & bugs
Open an issue at [github.com/KeiSei84/KeiSeiKit/issues](https://github.com/KeiSei84/KeiSeiKit/issues). A well-formed problem description is already half the solution. Open an issue at [github.com/KeiSeiLab/KeiSeiKit-1.0/issues](https://github.com/KeiSeiLab/KeiSeiKit-1.0/issues). A well-formed problem description is already half the solution.
## References ## References

View file

@ -68,7 +68,7 @@ curl -fsSL https://install.keisei.app | bash
curl -fsSL https://install.keisei.app | bash -s -- --profile=dev --yes # CI curl -fsSL https://install.keisei.app | bash -s -- --profile=dev --yes # CI
# Claude Code (primary target — full hook + agent integration) # Claude Code (primary target — full hook + agent integration)
/plugin marketplace add KeiSei84/KeiSeiKit-1.0 /plugin marketplace add KeiSeiLab/KeiSeiKit-1.0
/plugin install keisei@keisei-marketplace /plugin install keisei@keisei-marketplace
# Any MCP-compatible client (Cursor / Continue / Zed / Aider / etc) # Any MCP-compatible client (Cursor / Continue / Zed / Aider / etc)

View file

@ -12,7 +12,7 @@ Email `parfionovich@keilab.io` with a description and reproduction steps. PGP ke
## Supported versions ## Supported versions
Latest `v0.14.x` tag. Older versions accept fixes for CVEs only. Latest `v0.38.x` tag. Older versions accept fixes for CVEs only.
## Audit ## Audit

View file

@ -94,10 +94,6 @@ trigger = "fal.ai call needs to be wired into project source beyond a throwaway
target = "validator" target = "validator"
trigger = "generated assets include text / citations / claims that need RULE 0.4 verification before shipping" trigger = "generated assets include text / citations / claims that need RULE 0.4 verification before shipping"
[[handoff]]
target = "keimd-expert"
trigger = "user asks \"what assets already exist in this project\" — knowledge graph search, not fal.ai call"
[[handoff]] [[handoff]]
target = "critic" target = "critic"
trigger = "anti-pattern sweep after batch — are prompts / generated assets consistent / on-brand?" trigger = "anti-pattern sweep after batch — are prompts / generated assets consistent / on-brand?"

View file

@ -33,7 +33,7 @@ forbidden_domain = [
"IaC (Terraform/Pulumi/CDK) — hand off to infra-implementer-iac", "IaC (Terraform/Pulumi/CDK) — hand off to infra-implementer-iac",
"Dockerfiles or OCI images — hand off to infra-implementer-container", "Dockerfiles or OCI images — hand off to infra-implementer-container",
"Secrets management (Vault, sops, age) — hand off to infra-implementer-secrets", "Secrets management (Vault, sops, age) — hand off to infra-implementer-secrets",
"Hardcoded secrets in workflow YAML (RULE 0.8) — use `${{ secrets.NAME }}` / ENV refs", "Hardcoded secrets in workflow YAML (RULE 0.8) — use repo/org secret refs + ENV, never inline",
"Skipping build-cache steps — always cache cargo registry + target, node_modules, pip cache", "Skipping build-cache steps — always cache cargo registry + target, node_modules, pip cache",
] ]
output_extra_fields = [ output_extra_fields = [

View file

@ -198,8 +198,8 @@ edition = "2021"
rust-version = "1.77" rust-version = "1.77"
authors = ["Denis Parfionovich <parfionovich@keilab.io>"] authors = ["Denis Parfionovich <parfionovich@keilab.io>"]
license = "Apache-2.0" license = "Apache-2.0"
repository = "https://github.com/KeiSei84/KeiSeiKit-1.0" repository = "https://github.com/KeiSeiLab/KeiSeiKit-1.0"
homepage = "https://github.com/KeiSei84/KeiSeiKit-1.0" homepage = "https://github.com/KeiSeiLab/KeiSeiKit-1.0"
[workspace.dependencies] [workspace.dependencies]
clap = { version = "4", features = ["derive", "env"] } clap = { version = "4", features = ["derive", "env"] }

View file

@ -27,15 +27,6 @@ language = "toml"
[pipeline] [pipeline]
handoff = ["merger"] handoff = ["merger"]
[taxonomy]
kingdom = "role"
mechanism = "audit"
domain = "agent"
layer = "agent-substrate"
stage = "runtime"
stability = "stable"
language = "toml"
[lineage] [lineage]
parents = [] parents = []
creator = "ag-orchestrator-human" creator = "ag-orchestrator-human"

View file

@ -27,15 +27,6 @@ language = "toml"
[pipeline] [pipeline]
handoff = [] handoff = []
[taxonomy]
kingdom = "role"
mechanism = "merge"
domain = "agent"
layer = "agent-substrate"
stage = "runtime"
stability = "stable"
language = "toml"
[lineage] [lineage]
parents = [] parents = []
creator = "ag-orchestrator-human" creator = "ag-orchestrator-human"

View file

@ -19,7 +19,7 @@
], ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/KeiSei84/KeiSeiKit-1.0.git", "url": "git+https://github.com/KeiSeiLab/KeiSeiKit-1.0.git",
"directory": "_ts_packages/packages/mcp-server" "directory": "_ts_packages/packages/mcp-server"
}, },
"publishConfig": { "publishConfig": {

View file

@ -8,7 +8,7 @@
# #
# Usage from a fresh machine (private repo, gh CLI required for clone): # Usage from a fresh machine (private repo, gh CLI required for clone):
# gh auth login # gh auth login
# gh repo clone KeiSei84/KeiSeiKit-1.0 # gh repo clone KeiSeiLab/KeiSeiKit-1.0
# cd KeiSeiKit-1.0 && ./bootstrap.sh # cd KeiSeiKit-1.0 && ./bootstrap.sh
# #
# What it does (idempotent — re-running is safe): # What it does (idempotent — re-running is safe):
@ -164,7 +164,7 @@ fi
KIT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" KIT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ ! -f "$KIT_DIR/install.sh" ]; then if [ ! -f "$KIT_DIR/install.sh" ]; then
err "install.sh not found in $KIT_DIR — am I inside a KeiSeiKit checkout?" err "install.sh not found in $KIT_DIR — am I inside a KeiSeiKit checkout?"
err "if not: gh repo clone KeiSei84/KeiSeiKit-1.0 && cd KeiSeiKit-1.0 && ./bootstrap.sh" err "if not: gh repo clone KeiSeiLab/KeiSeiKit-1.0 && cd KeiSeiKit-1.0 && ./bootstrap.sh"
exit 1 exit 1
fi fi
log "checkout: $KIT_DIR" log "checkout: $KIT_DIR"

View file

@ -63,7 +63,7 @@ cd _primitives/_rust && cargo test --workspace 2>&1 | tail -5
## GitHub Releases status ## GitHub Releases status
6 tags pushed. Release workflow in `release.yml` triggers on tag push. Expected: 6 releases × (3 Rust tarballs + 5 MCP binaries + sha256 each) = ~48 assets. Check `github.com/KeiSei84/KeiSeiKit/releases` on wake — all tags should have attached assets within 10 min of push per prior v0.22.3 smoke. CI was re-triggered after Pro upgrade; confirm status there. 6 tags pushed. Release workflow in `release.yml` triggers on tag push. Expected: 6 releases × (3 Rust tarballs + 5 MCP binaries + sha256 each) = ~48 assets. Check `github.com/KeiSeiLab/KeiSeiKit-1.0/releases` on wake — all tags should have attached assets within 10 min of push per prior v0.22.3 smoke. CI was re-triggered after Pro upgrade; confirm status there.
## What substrate looks like now ## What substrate looks like now

View file

@ -8,7 +8,7 @@ Complete install guide. Quick-start lives in the main [README](../README.md#inst
| Path | Command | Best for | | Path | Command | Best for |
|---|---|---| |---|---|---|
| **Plugin** (v0.16+, recommended on Claude Code 2.1+) | `/plugin marketplace add KeiSei84/KeiSeiKit` then `/plugin install keisei@keisei-marketplace` | Agents + skills + hooks + MCP. Zero cargo build. See [PLUGIN.md](../PLUGIN.md). | | **Plugin** (v0.16+, recommended on Claude Code 2.1+) | `/plugin marketplace add KeiSeiLab/KeiSeiKit-1.0` then `/plugin install keisei@keisei-marketplace` | Agents + skills + hooks + MCP. Zero cargo build. See [PLUGIN.md](../PLUGIN.md). |
| **Classic** `./install.sh` | Below | Full kit incl. 47 Rust primitives + 13 shell primitives. Required for `ops` / `dev` / `full` profiles. | | **Classic** `./install.sh` | Below | Full kit incl. 47 Rust primitives + 13 shell primitives. Required for `ops` / `dev` / `full` profiles. |
## Prerequisites ## Prerequisites

View file

@ -14,7 +14,7 @@ mkdir -p "$BRAIN"/{bin,memory,artifacts,manifests}
## 2. Download MCP server binaries ## 2. Download MCP server binaries
```bash ```bash
BASE=https://github.com/KeiSei84/KeiSeiKit/releases/download/v0.21.0 BASE=https://github.com/KeiSeiLab/KeiSeiKit-1.0/releases/download/v0.21.0
cd "$BRAIN/bin" cd "$BRAIN/bin"
for n in darwin-arm64 darwin-x64 linux-x64 linux-arm64 windows-x64.exe; do for n in darwin-arm64 darwin-x64 linux-x64 linux-arm64 windows-x64.exe; do
curl -fL -O "$BASE/kei-mcp-server-$n" 2>/dev/null || echo "skipped $n" curl -fL -O "$BASE/kei-mcp-server-$n" 2>/dev/null || echo "skipped $n"

View file

@ -12,7 +12,7 @@ mkdir -p "$BRAIN"/{bin,memory,artifacts,manifests}
## 2. Download MCP server binaries ## 2. Download MCP server binaries
```bash ```bash
BASE=https://github.com/KeiSei84/KeiSeiKit/releases/download/v0.21.0 BASE=https://github.com/KeiSeiLab/KeiSeiKit-1.0/releases/download/v0.21.0
cd "$BRAIN/bin" cd "$BRAIN/bin"
for n in darwin-arm64 darwin-x64 linux-x64 windows-x64.exe; do for n in darwin-arm64 darwin-x64 linux-x64 windows-x64.exe; do
curl -fL -O "$BASE/kei-mcp-server-$n" curl -fL -O "$BASE/kei-mcp-server-$n"

View file

@ -18,7 +18,7 @@ New-Item -ItemType Directory -Path $BRAIN,"$BRAIN\bin","$BRAIN\memory","$BRAIN\a
## 2. Download MCP server binaries ## 2. Download MCP server binaries
```powershell ```powershell
$BASE = "https://github.com/KeiSei84/KeiSeiKit/releases/download/v0.21.0" $BASE = "https://github.com/KeiSeiLab/KeiSeiKit-1.0/releases/download/v0.21.0"
Push-Location "$BRAIN\bin" Push-Location "$BRAIN\bin"
$names = @( $names = @(

View file

@ -148,6 +148,26 @@ case "$PROFILE" in
esac esac
say "profile: $PROFILE" say "profile: $PROFILE"
# --- resolve profile -> primitive list (UNCONDITIONAL, SSoT) -------------
# Must run BEFORE any reader of PROFILE_PRIMS: the --no-execute plan block
# below, the --skip-prereqs path (which bypasses check_prereqs), and the
# conditional cargo gate in check_hard_prereqs. Previously this lived only
# inside check_prereqs, so --no-execute / --skip-prereqs saw PROFILE_PRIMS
# unbound and silently resolved to 0 primitives.
resolve_profile_prims
# --- skip heavy substrate workspace build for no-rust-primitive profiles --
# The agent assembler always compiles (tiny), but the 105-crate substrate
# workspace (kei-fork / kei-ledger / kei-cortex / ...) only matters for
# profiles that ship rust primitives. With no prebuilt release binaries,
# every install would otherwise fall back to a 5-15 min `cargo build
# --workspace`. Auto-skip keeps minimal / shell-only profiles fast. An
# explicit user-set KEI_SKIP_RUST always wins.
if [ -z "${KEI_SKIP_RUST:-}" ] && ! _profile_needs_cargo; then
export KEI_SKIP_RUST=1
say "no rust primitives in profile=$PROFILE -> skipping substrate workspace build (assembler only)"
fi
# --- welcome banner + onboarding wizard ---------------------------------- # --- welcome banner + onboarding wizard ----------------------------------
# Banner всегда EN — пользователь ещё не выбрал язык. # Banner всегда EN — пользователь ещё не выбрал язык.
# Wizard: TTY + нет ~/.claude/.onboarded + не задан KEISEI_SKIP_ONBOARD. # Wizard: TTY + нет ~/.claude/.onboarded + не задан KEISEI_SKIP_ONBOARD.

View file

@ -98,7 +98,15 @@ build_assembler() {
} }
# Run the built assembler in --in-place mode to write the agent .md files. # Run the built assembler in --in-place mode to write the agent .md files.
# Tolerant by design: a handful of stale/broken manifests (e.g. a handoff to
# an agent not shipped in this profile, or an un-substituted template field)
# must NOT abort the whole install — hooks, skills, settings still need to
# land. The assembler prints per-manifest FAIL lines for visibility, and the
# commit-time assembler-validate gate stays strict, so genuine breakage is
# still caught at authoring time.
generate_agents() { generate_agents() {
say "generating agent .md files (--in-place)" say "generating agent .md files (--in-place)"
AGENT_ROOT="$AGENTS_DIR" "$AGENTS_DIR/_assembler/target/release/assemble" --in-place if ! AGENT_ROOT="$AGENTS_DIR" "$AGENTS_DIR/_assembler/target/release/assemble" --in-place; then
warn "some agent manifests failed to assemble (see FAIL lines above) — continuing install"
fi
} }

View file

@ -28,7 +28,7 @@ Usage: ./install.sh [flags]
NOTE: this classic installer is for power users (Rust primitives, custom NOTE: this classic installer is for power users (Rust primitives, custom
profiles, full control). Most users should prefer the Claude Code plugin: profiles, full control). Most users should prefer the Claude Code plugin:
/plugin marketplace add KeiSei84/KeiSeiKit /plugin marketplace add KeiSeiLab/KeiSeiKit-1.0
/plugin install keisei@keisei-marketplace /plugin install keisei@keisei-marketplace
See README.md "Plugin install (v0.16+, recommended)" and PLUGIN.md for See README.md "Plugin install (v0.16+, recommended)" and PLUGIN.md for
details. The classic installer and the plugin can coexist — use whichever details. The classic installer and the plugin can coexist — use whichever

View file

@ -80,6 +80,13 @@ _jq_merge_hooks() {
) )
) )
) )
# statusLine (KeiSei tamagotchi): set ONLY when the target has none.
# Never clobber an existing statusLine. Fresh-install path drops the
# snippet verbatim, so this only matters when merging into a
# pre-existing settings.json.
| if (.statusLine // null) == null and ($add.statusLine // null) != null
then .statusLine = $add.statusLine
else . end
' "$target" > "$tmp" ' "$target" > "$tmp"
if [ -s "$tmp" ] && jq -e . "$tmp" >/dev/null 2>&1; then if [ -s "$tmp" ] && jq -e . "$tmp" >/dev/null 2>&1; then
mv "$tmp" "$target" mv "$tmp" "$target"

View file

@ -9,8 +9,29 @@
# Reads globals: $PROFILE, $CUSTOM_PRIMS, $MANIFEST. # Reads globals: $PROFILE, $CUSTOM_PRIMS, $MANIFEST.
# Sets global: $PROFILE_PRIMS (space-separated primitive names). # Sets global: $PROFILE_PRIMS (space-separated primitive names).
# Hard checks: cargo + jq. Exit 1 on missing — without them the install # Does the resolved profile contain at least one rust primitive? Only then
# (or the installed hooks afterwards) cannot function. # is a functional cargo toolchain a HARD requirement. Profiles like minimal
# (0 primitives) and shell-only customs build nothing and must install
# without Rust — README promises "minimal — NO Rust compile". Requires
# PROFILE_PRIMS already resolved (resolve_profile_prims, called by install.sh
# and at the top of check_prereqs).
_profile_needs_cargo() {
local p kind
for p in ${PROFILE_PRIMS:-}; do
kind="$(primitive_field "$p" kind 2>/dev/null || true)"
[ "$kind" = "rust" ] && return 0
done
return 1
}
# Hard checks: cargo + jq, both always required.
# cargo — the agent assembler (build_assembler) compiles a small rust binary
# to generate the agent .md files on EVERY profile, so cargo is
# non-negotiable. The heavy 105-crate substrate *workspace* build is
# a separate concern: install.sh auto-sets KEI_SKIP_RUST for profiles
# with no rust primitives so minimal stays fast (assembler only).
# jq — the installed hooks parse Claude Code JSON via jq and would abort
# tool calls without it.
check_hard_prereqs() { check_hard_prereqs() {
say "checking prerequisites" say "checking prerequisites"
if ! command -v cargo >/dev/null 2>&1; then if ! command -v cargo >/dev/null 2>&1; then
@ -103,9 +124,12 @@ check_soft_prereqs() {
fi fi
} }
# Top-level orchestrator: hard first (exit on miss), then resolve + soft. # Top-level orchestrator: resolve profile first (idempotent — install.sh
# already resolved it before the no-execute/skip-prereqs branches), so the
# conditional cargo gate in check_hard_prereqs can see PROFILE_PRIMS; then
# hard checks (exit on miss); then soft warnings.
check_prereqs() { check_prereqs() {
check_hard_prereqs
resolve_profile_prims resolve_profile_prims
check_hard_prereqs
check_soft_prereqs check_soft_prereqs
} }

View file

@ -11,7 +11,7 @@
# Path A — download from latest github release (fast, no Rust required): # Path A — download from latest github release (fast, no Rust required):
# 1. Detect platform via uname → Rust target triple. # 1. Detect platform via uname → Rust target triple.
# 2. Fetch keisei-${TARGET}.tar.gz from # 2. Fetch keisei-${TARGET}.tar.gz from
# https://github.com/KeiSei84/KeiSeiKit-1.0/releases/latest/download/ # https://github.com/KeiSeiLab/KeiSeiKit-1.0/releases/latest/download/
# 3. Verify sha256. # 3. Verify sha256.
# 4. Extract into target/release/. # 4. Extract into target/release/.
# #
@ -62,7 +62,7 @@ download_release_tarball() {
local target="$1" local target="$1"
[ -n "$target" ] || return 1 [ -n "$target" ] || return 1
local tarball="keisei-${target}.tar.gz" local tarball="keisei-${target}.tar.gz"
local url="https://github.com/KeiSei84/KeiSeiKit-1.0/releases/latest/download/${tarball}" local url="https://github.com/KeiSeiLab/KeiSeiKit-1.0/releases/latest/download/${tarball}"
local tmp local tmp
tmp="$(mktemp -d -t keisei-prebuild-XXXX 2>/dev/null)" || return 1 tmp="$(mktemp -d -t keisei-prebuild-XXXX 2>/dev/null)" || return 1
command -v curl >/dev/null 2>&1 || { rm -rf "$tmp"; return 1; } command -v curl >/dev/null 2>&1 || { rm -rf "$tmp"; return 1; }

View file

@ -24,7 +24,8 @@ setup_target_dirs() {
"$AGENTS_DIR/_generated" \ "$AGENTS_DIR/_generated" \
"$HOOKS_DIR" \ "$HOOKS_DIR" \
"$SKILLS_DIR/new-agent" \ "$SKILLS_DIR/new-agent" \
"$HOME_DIR/.claude/memory" "$HOME_DIR/.claude/memory" \
"$HOME_DIR/.claude/scripts"
} }
# Write a stub MEMORY.md if the user has no index yet. We never overwrite. # Write a stub MEMORY.md if the user has no index yet. We never overwrite.
@ -65,6 +66,23 @@ copy_sleep_scripts() {
fi fi
} }
# KeiSei tamagotchi statusline — copy the renderer + state updater into
# ~/.claude/scripts/. Zero binary deps (pure bash, state under ~/.claude/pet/),
# always available regardless of profile. The statusLine + pet-update hooks
# are wired into settings.json by the settings-snippet merge (lib-hooks.sh).
copy_pet_scripts() {
local pet_sh src dst="$HOME_DIR/.claude/scripts"
[ -d "$KIT_DIR/scripts" ] || return 0
mkdir -p "$dst"
for pet_sh in keisei-pet.sh keisei-pet-update.sh; do
src="$KIT_DIR/scripts/$pet_sh"
if [ -f "$src" ]; then
cp -f "$src" "$dst/$pet_sh"
chmod +x "$dst/$pet_sh"
fi
done
}
# Clean slate: drop every shell .sh + rust crate dir from the installed set. # Clean slate: drop every shell .sh + rust crate dir from the installed set.
# FAST (no per-rust rebuild). A single regenerate_rust_workspace at the end # FAST (no per-rust rebuild). A single regenerate_rust_workspace at the end
# of install_primitives handles the final state. # of install_primitives handles the final state.
@ -99,6 +117,7 @@ install_profile_primitives() {
run_primitives_phase() { run_primitives_phase() {
copy_primitives_meta copy_primitives_meta
copy_sleep_scripts copy_sleep_scripts
copy_pet_scripts
say "resolving primitives for profile=$PROFILE" say "resolving primitives for profile=$PROFILE"
clean_slate_primitives clean_slate_primitives
install_profile_primitives install_profile_primitives

View file

@ -0,0 +1,126 @@
#!/usr/bin/env bash
# KeiSei pet state updater — called by hooks to change the pet's mood.
# Usage: keisei-pet-update.sh <event>
# Events: prompt | rust_write | github_block | python_no_reason |
# modal_cost | patent_filed | concept_saved | secret_leak |
# test_pass | test_fail | sleep | rule_violation | idle
#
# The hook may also pipe JSON tool-context on stdin; we ignore it for now
# (future: parse tool_input to make reactions smarter).
set -u
STATE_DIR="${HOME}/.claude/pet"
STATE="${STATE_DIR}/state"
HISTORY="${STATE_DIR}/history.log"
mkdir -p "$STATE_DIR"
# Load current state
mood="neutral"
message=""
since=$(date +%s)
rust_today=0
patents_today=0
violations=0
# shellcheck source=/dev/null
[ -f "$STATE" ] && source "$STATE" 2>/dev/null || true
# Daily counter reset (if state last updated yesterday)
last_day=${day:-}
today=$(date +%Y-%m-%d)
if [ "$last_day" != "$today" ]; then
rust_today=0
patents_today=0
violations=0
fi
event="${1:-}"
now=$(date +%s)
# Discard stdin quickly so hook doesn't block
if [ ! -t 0 ]; then
cat >/dev/null 2>&1 || true
fi
case "$event" in
prompt)
mood="thinking"
message="考えてる..."
;;
rust_write)
rust_today=$((rust_today + 1))
mood="happy"
message="構造式 ✓ Rust"
;;
github_block)
mood="angry"
message="RULE 0.1! no github"
violations=$((violations + 1))
;;
python_no_reason)
mood="alert"
message="Python? 理由は? (RULE 0.2)"
;;
modal_cost)
mood="alert"
message="\$\$ compute check"
;;
patent_filed)
mood="proud"
patents_today=$((patents_today + 1))
message="特許 filed!"
;;
concept_saved)
mood="happy"
message="💡 concept saved"
;;
secret_leak)
mood="angry"
message="SECRET! RULE 0.8"
violations=$((violations + 1))
;;
test_pass)
mood="happy"
message="テスト ✓"
;;
test_fail)
mood="sad"
message="テスト ✗"
;;
rule_violation)
mood="angry"
message="rule violation ⚠"
violations=$((violations + 1))
;;
sleep)
mood="sleep"
message="zzz"
;;
*)
# unknown event — no-op, keep current state
:
;;
esac
# Write state atomically
tmp="${STATE}.tmp.$$"
cat > "$tmp" <<EOF
mood="$mood"
message="$message"
since=$now
day="$today"
rust_today=$rust_today
patents_today=$patents_today
violations=$violations
EOF
mv "$tmp" "$STATE"
# Rolling history (last 50 events)
printf "%s %s\n" "$(date -u +%FT%TZ)" "$event" >> "$HISTORY"
if [ -f "$HISTORY" ] && [ "$(wc -l < "$HISTORY")" -gt 50 ]; then
tail -50 "$HISTORY" > "${HISTORY}.tmp" && mv "${HISTORY}.tmp" "$HISTORY"
fi
# Hooks in Claude Code expect exit 0 to pass through
exit 0

67
scripts/keisei-pet.sh Normal file
View file

@ -0,0 +1,67 @@
#!/usr/bin/env bash
# KeiSei tamagotchi — statusline renderer.
# Called by Claude Code on every prompt render. Outputs ONE line.
# Reads state from ~/.claude/pet/state (written by keisei-pet-update.sh).
set -u
# Discard any stdin (Claude Code may pipe session JSON to statusLine)
if [ ! -t 0 ]; then
cat >/dev/null 2>&1 || true
fi
STATE="${HOME}/.claude/pet/state"
# Defaults (if state file missing/stale)
mood="neutral"
message=""
since=$(date +%s)
rust_today=0
patents_today=0
violations=0
# shellcheck source=/dev/null
[ -f "$STATE" ] && source "$STATE" 2>/dev/null || true
now=$(date +%s)
idle=$((now - since))
# Idle >5 min → pet sleeps (unless it's angry/alert about something)
if [ "$idle" -gt 300 ] && [ "$mood" != "angry" ] && [ "$mood" != "alert" ]; then
mood="sleep"
message="zzz"
fi
# Face + color by mood
case "$mood" in
happy) face="(ᵔᴥᵔ)"; color=$'\033[32m' ;; # green
proud) face="(•̀ᴗ•́)و"; color=$'\033[1;32m';; # bright green
thinking) face="(⊙.⊙)"; color=$'\033[36m' ;; # cyan
alert) face="(ʘᴗʘ)"; color=$'\033[33m' ;; # yellow
angry) face="(ò_ó)"; color=$'\033[31m' ;; # red
sad) face="(╥﹏╥)"; color=$'\033[34m' ;; # blue
sleep) face="(-.-)"; color=$'\033[2;37m';; # dim gray
*) face="(•ᴗ•)"; color=$'\033[37m' ;; # white (neutral)
esac
dim=$'\033[2m'
reset=$'\033[0m'
# stats line (compact)
stats=""
[ "$rust_today" -gt 0 ] && stats+=" 🦀${rust_today}"
[ "$patents_today" -gt 0 ] && stats+=" 📜${patents_today}"
[ "$violations" -gt 0 ] && stats+="${violations}"
# Project name from PWD
proj="${PWD##*/}"
[ -z "$proj" ] && proj="~"
# Render: face | message | stats | project
# Keep it ≤ one line
printf "%s%s%s %s%s%s%s%s %s%s%s" \
"$color" "$face" "$reset" \
"$dim" "$message" "$reset" \
"$stats" \
"" \
"$dim" "📁 $proj" "$reset"

View file

@ -1,5 +1,10 @@
{ {
"_comment": "Merge these entries into your ~/.claude/settings.json under the matching keys. If you already have PostToolUse/PreToolUse/Stop arrays, append the objects below to them instead of overwriting. install.sh --activate-hooks automates the merge and de-dupes by hooks[].command.", "_comment": "Merge these entries into your ~/.claude/settings.json under the matching keys. If you already have PostToolUse/PreToolUse/Stop arrays, append the objects below to them instead of overwriting. install.sh --activate-hooks automates the merge and de-dupes by hooks[].command. statusLine (the KeiSei tamagotchi) is set ONLY when you have none — an existing statusLine is never clobbered.",
"statusLine": {
"type": "command",
"command": "~/.claude/scripts/keisei-pet.sh",
"padding": 0
},
"hooks": { "hooks": {
"PostToolUse": [ "PostToolUse": [
{ {
@ -18,6 +23,10 @@
"type": "command", "type": "command",
"command": "~/.claude/hooks/post-write-check.sh", "command": "~/.claude/hooks/post-write-check.sh",
"statusMessage": "post-write checks..." "statusMessage": "post-write checks..."
},
{
"type": "command",
"command": "FILE=$(cat | jq -r '.tool_input.file_path // empty'); [ -n \"$FILE\" ] && [ \"${FILE##*.}\" = 'rs' ] && ~/.claude/scripts/keisei-pet-update.sh rust_write; exit 0"
} }
] ]
}, },
@ -113,6 +122,10 @@
"type": "command", "type": "command",
"command": "~/.claude/hooks/no-github-push.sh", "command": "~/.claude/hooks/no-github-push.sh",
"statusMessage": "no-github-push guard (RULE 0.1)..." "statusMessage": "no-github-push guard (RULE 0.1)..."
},
{
"type": "command",
"command": "CMD=$(cat | jq -r '.tool_input.command // empty'); echo \"$CMD\" | grep -qiE 'git push.*github|gh repo (create|push|sync)' && ~/.claude/scripts/keisei-pet-update.sh github_block; exit 0"
} }
] ]
}, },
@ -207,6 +220,10 @@
"type": "command", "type": "command",
"command": "~/.claude/hooks/chat-numeric-prewarn.sh", "command": "~/.claude/hooks/chat-numeric-prewarn.sh",
"statusMessage": "chat-numeric-prewarn (RULE 0.18)..." "statusMessage": "chat-numeric-prewarn (RULE 0.18)..."
},
{
"type": "command",
"command": "~/.claude/scripts/keisei-pet-update.sh prompt"
} }
] ]
} }
@ -238,6 +255,10 @@
"type": "command", "type": "command",
"command": "~/.claude/hooks/chat-numeric-postflag.sh", "command": "~/.claude/hooks/chat-numeric-postflag.sh",
"statusMessage": "chat-numeric-postflag (RULE 0.18)..." "statusMessage": "chat-numeric-postflag (RULE 0.18)..."
},
{
"type": "command",
"command": "~/.claude/scripts/keisei-pet-update.sh sleep"
} }
] ]
} }