fix(install): make fresh install complete + ship tamagotchi #1

Merged
denis merged 1 commit from fix/install-prod-ready-pet into main 2026-05-20 18:50:10 +00:00
28 changed files with 330 additions and 60 deletions

View file

@ -1,21 +1,21 @@
{
"name": "keisei-marketplace",
"owner": {
"name": "KeiSei84",
"url": "https://github.com/KeiSei84"
"name": "Denis Parfionovich",
"url": "https://github.com/KeiSeiLab"
},
"metadata": {
"description": "KeiSei Constructor-Pattern kits and primitives for Claude Code",
"version": "0.16.0"
"version": "0.38.0"
},
"plugins": [
{
"name": "keisei",
"source": {
"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",
"version": "0.16.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.",
"version": "0.38.0",
"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": {
"name": "KeiSei",
"url": "https://github.com/KeiSei84"
"name": "Denis Parfionovich",
"url": "https://github.com/KeiSeiLab"
},
"homepage": "https://github.com/KeiSei84/KeiSeiKit",
"repository": "https://github.com/KeiSei84/KeiSeiKit",
"homepage": "https://github.com/KeiSeiLab/KeiSeiKit-1.0",
"repository": "https://github.com/KeiSeiLab/KeiSeiKit-1.0",
"license": "Apache-2.0",
"keywords": [
"constructor-pattern",

View file

@ -383,5 +383,5 @@ Per RULE 0.13 (orchestrator branch first), each phase = orchestrator-created bra
## Sources
- `/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.

View file

@ -6,7 +6,7 @@ This document describes the plugin-format install path (v0.16+) and how it relat
```bash
# One-time
/plugin marketplace add KeiSei84/KeiSeiKit
/plugin marketplace add KeiSeiLab/KeiSeiKit-1.0
# Install
/plugin install keisei@keisei-marketplace
```
@ -50,7 +50,7 @@ Paths inside `hooks/hooks.json` use `${CLAUDE_PLUGIN_ROOT}` (expanded by Claude
**For plugin install:**
- 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:**
- `@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
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

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
# 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
# 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
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

View file

@ -94,10 +94,6 @@ trigger = "fal.ai call needs to be wired into project source beyond a throwaway
target = "validator"
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]]
target = "critic"
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",
"Dockerfiles or OCI images — hand off to infra-implementer-container",
"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",
]
output_extra_fields = [

View file

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

View file

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

View file

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

View file

@ -19,7 +19,7 @@
],
"repository": {
"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"
},
"publishConfig": {

View file

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

View file

@ -63,7 +63,7 @@ cd _primitives/_rust && cargo test --workspace 2>&1 | tail -5
## 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

View file

@ -8,7 +8,7 @@ Complete install guide. Quick-start lives in the main [README](../README.md#inst
| 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. |
## Prerequisites

View file

@ -14,7 +14,7 @@ mkdir -p "$BRAIN"/{bin,memory,artifacts,manifests}
## 2. Download MCP server binaries
```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"
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"

View file

@ -12,7 +12,7 @@ mkdir -p "$BRAIN"/{bin,memory,artifacts,manifests}
## 2. Download MCP server binaries
```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"
for n in darwin-arm64 darwin-x64 linux-x64 windows-x64.exe; do
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
```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"
$names = @(

View file

@ -148,6 +148,26 @@ case "$PROFILE" in
esac
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 ----------------------------------
# Banner всегда EN — пользователь ещё не выбрал язык.
# 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.
# 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() {
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
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
See README.md "Plugin install (v0.16+, recommended)" and PLUGIN.md for
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"
if [ -s "$tmp" ] && jq -e . "$tmp" >/dev/null 2>&1; then
mv "$tmp" "$target"

View file

@ -9,8 +9,29 @@
# Reads globals: $PROFILE, $CUSTOM_PRIMS, $MANIFEST.
# Sets global: $PROFILE_PRIMS (space-separated primitive names).
# Hard checks: cargo + jq. Exit 1 on missing — without them the install
# (or the installed hooks afterwards) cannot function.
# Does the resolved profile contain at least one rust primitive? Only then
# 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() {
say "checking prerequisites"
if ! command -v cargo >/dev/null 2>&1; then
@ -103,9 +124,12 @@ check_soft_prereqs() {
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_hard_prereqs
resolve_profile_prims
check_hard_prereqs
check_soft_prereqs
}

View file

@ -11,7 +11,7 @@
# Path A — download from latest github release (fast, no Rust required):
# 1. Detect platform via uname → Rust target triple.
# 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.
# 4. Extract into target/release/.
#
@ -62,7 +62,7 @@ download_release_tarball() {
local target="$1"
[ -n "$target" ] || return 1
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
tmp="$(mktemp -d -t keisei-prebuild-XXXX 2>/dev/null)" || 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" \
"$HOOKS_DIR" \
"$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.
@ -65,6 +66,23 @@ copy_sleep_scripts() {
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.
# FAST (no per-rust rebuild). A single regenerate_rust_workspace at the end
# of install_primitives handles the final state.
@ -99,6 +117,7 @@ install_profile_primitives() {
run_primitives_phase() {
copy_primitives_meta
copy_sleep_scripts
copy_pet_scripts
say "resolving primitives for profile=$PROFILE"
clean_slate_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": {
"PostToolUse": [
{
@ -18,6 +23,10 @@
"type": "command",
"command": "~/.claude/hooks/post-write-check.sh",
"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",
"command": "~/.claude/hooks/no-github-push.sh",
"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",
"command": "~/.claude/hooks/chat-numeric-prewarn.sh",
"statusMessage": "chat-numeric-prewarn (RULE 0.18)..."
},
{
"type": "command",
"command": "~/.claude/scripts/keisei-pet-update.sh prompt"
}
]
}
@ -238,6 +255,10 @@
"type": "command",
"command": "~/.claude/hooks/chat-numeric-postflag.sh",
"statusMessage": "chat-numeric-postflag (RULE 0.18)..."
},
{
"type": "command",
"command": "~/.claude/scripts/keisei-pet-update.sh sleep"
}
]
}