fix(install): make install.sh idempotent + add onboard-project.sh
- install.sh: no longer exits early when ~/.automaton exists. Skips the clone but runs all setup (VRAM detection, guards, self-improvement loop, virtualenv). Both curl|bash and git-clone + ./install.sh now work correctly. - onboard-project.sh: new script that bootstraps automaton in a project — creates .automaton/ skeleton, detects models, writes config.md, inits git, installs hooks, adds .gitignore entries. - README.md: fix install flow docs (curl|bash + clone-then-run), add onboard-project.sh as Option A for project setup
This commit is contained in:
@@ -6,22 +6,28 @@ A contract-based operating system for LLM agents, designed to enforce discipline
|
||||
|
||||
Before you can use the framework in any project, you must install the core logic into your local environment.
|
||||
|
||||
**Run these commands in your terminal:**
|
||||
Choose one of the following methods:
|
||||
|
||||
### Option A: One-liner (curl pipe, recommended)
|
||||
|
||||
```bash
|
||||
# Clone the framework into the global config directory
|
||||
git clone <your-git-url> ~/.automaton
|
||||
|
||||
# Enter the directory
|
||||
cd ~/.automaton
|
||||
|
||||
# Make the installation script executable and run it
|
||||
# You must provide the git URL as the first argument
|
||||
chmod +x install.sh
|
||||
./install.sh <your-git-url>
|
||||
curl -fsSL https://raw.githubusercontent.com/<your-org>/automaton/main/scripts/install.sh | bash -s -- <your-git-url>
|
||||
```
|
||||
|
||||
The git URL is required because the framework uses it for self-updates and the self-improvement loop. Choose carefully -- it cannot be changed later without reinstalling.
|
||||
This clones the framework to `~/.automaton/`, runs VRAM detection, installs pre-edit guards, creates the self-improvement loop, and sets up the Python virtualenv.
|
||||
|
||||
### Option B: Clone first
|
||||
|
||||
```bash
|
||||
git clone <your-git-url> ~/.automaton
|
||||
bash ~/.automaton/scripts/install.sh
|
||||
```
|
||||
|
||||
The script detects that `~/.automaton` already exists, skips the clone, and runs all setup steps (VRAM detection, guards, loop, virtualenv).
|
||||
|
||||
### Both methods do the same thing
|
||||
|
||||
The git URL is required on fresh install because the framework uses it for self-updates and the self-improvement loop. Choose carefully -- it cannot be changed later without reinstalling.
|
||||
|
||||
*Note: This creates the "brain" of the framework (prompts, state machines, and rules) in your home directory. A self-improvement loop is created and scheduled by default (see Loop Engineering below).*
|
||||
|
||||
@@ -49,7 +55,24 @@ If a project was set up under the old model (with copies of framework files), it
|
||||
|
||||
Once the framework is installed globally, you must "onboard" every individual project you work on.
|
||||
|
||||
### Option A: The Agent-Driven Way (Recommended)
|
||||
### Option A: The Onboarding Script (Recommended)
|
||||
|
||||
```bash
|
||||
bash ~/.automaton/scripts/onboard-project.sh /path/to/project
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Create `.automaton/` skeleton if missing.
|
||||
2. Run `detect_models.py --write` to probe local models (falls back to a minimal `models.json`).
|
||||
3. Generate `config.md` with VRAM recommendations.
|
||||
4. Write `project-name.md` from the directory name.
|
||||
5. Initialize git if not already a repo.
|
||||
6. Install git hooks (pre-commit + pre-push).
|
||||
7. Add automaton entries to `.gitignore`.
|
||||
8. Run `status.py --audit` to verify the setup.
|
||||
|
||||
### Option B: The Agent-Driven Way
|
||||
|
||||
If you want the agent to handle the configuration for you, navigate to your project root and run:
|
||||
|
||||
> *"Onboard this project into automaton."
|
||||
@@ -60,17 +83,21 @@ The agent will automatically:
|
||||
3. Generate your `.agent.md` and `.rules.md` files.
|
||||
4. Initiate the "Exploration Ritual" to understand your codebase.
|
||||
|
||||
### Option B: The Manual Way
|
||||
If you prefer to set it up manually, create a `.automaton/` directory in your project root and add:
|
||||
- `.agent.md`: Project-specific configuration (Mode, rules, etc.).
|
||||
- `.rules.md`: Project-specific constraints and past failure modes.
|
||||
### Option C: The Manual Way
|
||||
If you prefer to set it up manually:
|
||||
|
||||
Then install the git pre-commit hook:
|
||||
```bash
|
||||
ln -sf ~/.automaton/scripts/git-hooks/pre-commit .git/hooks/pre-commit
|
||||
# Create the automaton directory
|
||||
mkdir -p .automaton/tasks .automaton/loops .automaton/design
|
||||
|
||||
# Install git hooks
|
||||
bash ~/.automaton/scripts/install-hooks.sh .
|
||||
|
||||
# Configure your model(s)
|
||||
python3 ~/.automaton/scripts/detect_models.py --write --project .
|
||||
```
|
||||
|
||||
This hook blocks commits when no task is in `implement` or `doc_review` phase, preventing accidental code changes without a tracked task.
|
||||
Then add `.agent.md` and `.rules.md` for the agent.
|
||||
|
||||
### The Self-Improvement Loop is framework-scoped
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
python3 "/Users/laptran/.automaton/scripts/status.py" --cleanup-done --days 7 --project "/private/var/folders/f5/yv0dzbnx47x3yp8sc_2519gh0000gn/T/pytest-of-laptran/pytest-127/test_uninstall_via_disabled_re0"
|
||||
python3 "/Users/laptran/.automaton/scripts/status.py" --cleanup-done --days 7 --project "/private/var/folders/f5/yv0dzbnx47x3yp8sc_2519gh0000gn/T/pytest-of-laptran/pytest-128/test_uninstall_via_disabled_re0"
|
||||
|
||||
+31
-25
@@ -3,27 +3,39 @@ set -e
|
||||
|
||||
FRAMEWORK_DIR="$HOME/.automaton"
|
||||
|
||||
if [ -d "$FRAMEWORK_DIR" ]; then
|
||||
echo "automaton already installed at $FRAMEWORK_DIR"
|
||||
echo "Run './update.sh' to update."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
GIT_URL="${1:-}"
|
||||
if [ -z "$GIT_URL" ]; then
|
||||
echo "ERROR: Git URL required."
|
||||
echo "Usage: ./install.sh <git-url>"
|
||||
echo "Example: ./install.sh https://github.com/user/automaton.git"
|
||||
|
||||
if [ ! -d "$FRAMEWORK_DIR" ]; then
|
||||
# Fresh install — need a Git URL to clone
|
||||
if [ -z "$GIT_URL" ]; then
|
||||
echo "ERROR: Git URL required for fresh install."
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " curl -fsSL https://raw.githubusercontent.com/<user>/automaton/main/scripts/install.sh | bash -s -- <git-url>"
|
||||
echo ""
|
||||
echo " --- or ---"
|
||||
echo ""
|
||||
echo " git clone <git-url> ~/.automaton"
|
||||
echo " bash ~/.automaton/scripts/install.sh"
|
||||
echo ""
|
||||
echo "The framework is cloned to ~/.automaton. Choose your URL carefully"
|
||||
echo "as it cannot be changed later without reinstalling."
|
||||
exit 1
|
||||
fi
|
||||
echo "Cloning automaton from $GIT_URL to $FRAMEWORK_DIR..."
|
||||
git clone "$GIT_URL" "$FRAMEWORK_DIR"
|
||||
echo ""
|
||||
else
|
||||
echo "automaton already installed at $FRAMEWORK_DIR — running setup steps..."
|
||||
if [ -n "$GIT_URL" ]; then
|
||||
echo "Note: Git URL argument ignored because ~/.automaton already exists."
|
||||
echo "To update, run: cd ~/.automaton && ./update.sh"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "Cloning automaton from $GIT_URL to $FRAMEWORK_DIR..."
|
||||
git clone "$GIT_URL" "$FRAMEWORK_DIR"
|
||||
# --- Everything below is idempotent and runs on both fresh and existing installs ---
|
||||
|
||||
echo ""
|
||||
echo "=== VRAM / Context Detection ==="
|
||||
echo "Detecting your system's VRAM to recommend task decomposition settings..."
|
||||
echo ""
|
||||
@@ -31,7 +43,7 @@ echo ""
|
||||
# Run VRAM detection script if it exists
|
||||
if [ -f "$FRAMEWORK_DIR/scripts/vram_detect.py" ]; then
|
||||
# Run in project-dir context so it can read framework overhead
|
||||
detection_output=$(cd "$FRAMEWORK_DIR" && python3 "$FRAMEWORK_DIR/scripts/vram_detect.py" 2>&1)
|
||||
detection_output=$(cd "$FRAMEWORK_DIR" && python3 "$FRAMEWORK_DIR/scripts/vram_detect.py" 2>&1 || true)
|
||||
|
||||
# Extract JSON output (the block after "=== JSON Output ===")
|
||||
json_output=$(echo "$detection_output" | sed -n '/=== JSON Output ===/,$p' | tail -n +2)
|
||||
@@ -40,12 +52,9 @@ if [ -f "$FRAMEWORK_DIR/scripts/vram_detect.py" ]; then
|
||||
echo "$detection_output"
|
||||
|
||||
# Extract key values from JSON using Python
|
||||
recommended_k=$(echo "$json_output" | python3 -c 'import json,sys; print(json.load(sys.stdin)["recommended_k"])')
|
||||
max_peak_kb=$(echo "$json_output" | python3 -c 'import json,sys; print(json.load(sys.stdin)["max_peak_context_kb"])')
|
||||
headroom=$(echo "$json_output" | python3 -c 'import json,sys; print(json.load(sys.stdin)["headroom"])')
|
||||
gpu_vram=$(echo "$json_output" | python3 -c 'import json,sys; print(json.load(sys.stdin)["gpu_vram_gb"])')
|
||||
ram_gb=$(echo "$json_output" | python3 -c 'import json,sys; print(json.load(sys.stdin)["ram_gb"])')
|
||||
model_context=$(echo "$json_output" | python3 -c 'import json,sys; print(json.load(sys.stdin)["model_context_kb"])')
|
||||
recommended_k=$(echo "$json_output" | python3 -c 'import json,sys; print(json.load(sys.stdin)["recommended_k"])' 2>/dev/null || echo "?")
|
||||
max_peak_kb=$(echo "$json_output" | python3 -c 'import json,sys; print(json.load(sys.stdin)["max_peak_context_kb"])' 2>/dev/null || echo "?")
|
||||
headroom=$(echo "$json_output" | python3 -c 'import json,sys; print(json.load(sys.stdin)["headroom"])' 2>/dev/null || echo "?")
|
||||
|
||||
echo ""
|
||||
echo "=== Recommended VRAM Configuration ==="
|
||||
@@ -72,11 +81,8 @@ echo ""
|
||||
echo "Installation complete."
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. cd into a project and run the onboarding prompt"
|
||||
echo " 2. In each project that uses git, install the automaton hooks:"
|
||||
echo " bash ~/.automaton/scripts/install-hooks.sh /path/to/project"
|
||||
echo ""
|
||||
echo "These hooks block commits and pushes when no task is in an edit-allowed phase."
|
||||
echo " 1. Onboard a project: bash ~/.automaton/scripts/onboard-project.sh /path/to/project"
|
||||
echo " 2. Or tell your agent: 'Onboard this project into automaton'"
|
||||
echo ""
|
||||
|
||||
# Register pre-edit guards for detected harnesses
|
||||
|
||||
Executable
+184
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env bash
|
||||
# onboard-project.sh — Bootstrap automaton in a new or existing project.
|
||||
#
|
||||
# Usage:
|
||||
# bash ~/.automaton/scripts/onboard-project.sh /path/to/project
|
||||
#
|
||||
# Creates .automaton/ skeleton, detects models, creates config, inits git,
|
||||
# installs hooks, and verifies everything works.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
FRAMEWORK_DIR="$HOME/.automaton"
|
||||
PROJECT_DIR="${1:-}"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
info() { echo -e "${BLUE}INFO:${NC} $1"; }
|
||||
ok() { echo -e "${GREEN}OK:${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}WARN:${NC} $1"; }
|
||||
error() { echo -e "${RED}ERROR:${NC} $1"; }
|
||||
|
||||
# --- Argument checks ---
|
||||
if [ -z "$PROJECT_DIR" ]; then
|
||||
error "Usage: bash ~/.automaton/scripts/onboard-project.sh /path/to/project"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROJECT_DIR="$(cd "$PROJECT_DIR" 2>/dev/null && pwd)" || true
|
||||
if [ -z "$PROJECT_DIR" ] || [ ! -d "$PROJECT_DIR" ]; then
|
||||
echo ""
|
||||
error "'$1' does not exist."
|
||||
echo " Create it first: mkdir -p '$1'"
|
||||
echo " Then re-run this script."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$FRAMEWORK_DIR/scripts" ]; then
|
||||
error "Framework not found at $FRAMEWORK_DIR."
|
||||
echo " Install the framework first:"
|
||||
echo " curl -fsSL https://raw.githubusercontent.com/<user>/automaton/main/scripts/install.sh | bash -s -- <git-url>"
|
||||
echo " Or: git clone <git-url> ~/.automaton && bash ~/.automaton/scripts/install.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo " Automaton Project Onboarding"
|
||||
echo " Project: $PROJECT_DIR"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# --- Step 1: Create .automaton/ skeleton ---
|
||||
AUTO_DIR="$PROJECT_DIR/.automaton"
|
||||
if [ -d "$AUTO_DIR" ]; then
|
||||
warn "$AUTO_DIR already exists — skipping skeleton creation"
|
||||
else
|
||||
info "Creating .automaton/ skeleton..."
|
||||
mkdir -p "$AUTO_DIR/tasks" "$AUTO_DIR/loops" "$AUTO_DIR/design"
|
||||
ok "Created $AUTO_DIR/"
|
||||
fi
|
||||
|
||||
# --- Step 2: Models ---
|
||||
MODELS_FILE="$AUTO_DIR/models.json"
|
||||
if [ -f "$MODELS_FILE" ]; then
|
||||
warn "$MODELS_FILE already exists — skipping model detection"
|
||||
else
|
||||
info "Probing local models..."
|
||||
if python3 "$FRAMEWORK_DIR/scripts/detect_models.py" --write --project "$PROJECT_DIR" 2>/dev/null; then
|
||||
ok "Detected models written to $MODELS_FILE"
|
||||
else
|
||||
info "Auto-detection failed. Creating minimal models.json..."
|
||||
cat > "$MODELS_FILE" <<- 'EOF'
|
||||
{
|
||||
"models": [
|
||||
{"name": "default-model", "provider": "local", "context": 32768}
|
||||
],
|
||||
"default": "default-model"
|
||||
}
|
||||
EOF
|
||||
warn "Edit $MODELS_FILE to set your actual model(s)."
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Step 3: Config ---
|
||||
CONFIG_FILE="$AUTO_DIR/config.md"
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
warn "$CONFIG_FILE already exists — skipping"
|
||||
else
|
||||
info "Creating config.md..."
|
||||
PROJECT_NAME="$(basename "$PROJECT_DIR")"
|
||||
if [ -f "$FRAMEWORK_DIR/scripts/vram_detect.py" ]; then
|
||||
vram_output=$(cd "$FRAMEWORK_DIR" && python3 "$FRAMEWORK_DIR/scripts/vram_detect.py" 2>/dev/null || true)
|
||||
json_part=$(echo "$vram_output" | sed -n '/=== JSON Output ===/,$p' | tail -n +2)
|
||||
recommended=$(echo "$json_part" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("recommended_k","16"))' 2>/dev/null || echo "16")
|
||||
else
|
||||
recommended="16"
|
||||
fi
|
||||
cat > "$CONFIG_FILE" <<- EOF
|
||||
# $PROJECT_NAME — Automaton Configuration
|
||||
|
||||
## VRAM Configuration
|
||||
- **Auto-detect**: Yes
|
||||
- **Target context**: ${recommended}k tokens
|
||||
- **Headroom**: 25%
|
||||
- **Max peak context per sub-task**: $((recommended * 3 / 4))k tokens
|
||||
|
||||
## Model Configuration
|
||||
# Uses models.json for model divergence enforcement.
|
||||
# Default model is read from models.json's "default" key.
|
||||
EOF
|
||||
ok "Created $CONFIG_FILE"
|
||||
fi
|
||||
|
||||
# --- Step 4: Project name ---
|
||||
NAME_FILE="$AUTO_DIR/project-name.md"
|
||||
if [ -f "$NAME_FILE" ]; then
|
||||
warn "$NAME_FILE already exists — skipping"
|
||||
else
|
||||
PROJECT_NAME="$(basename "$PROJECT_DIR")"
|
||||
echo "$PROJECT_NAME" > "$NAME_FILE"
|
||||
ok "Created $NAME_FILE ($PROJECT_NAME)"
|
||||
fi
|
||||
|
||||
# --- Step 5: Git ---
|
||||
GIT_DIR="$PROJECT_DIR/.git"
|
||||
if [ -d "$GIT_DIR" ]; then
|
||||
ok "Git repository already initialized"
|
||||
else
|
||||
info "Initializing git repository..."
|
||||
cd "$PROJECT_DIR" && git init
|
||||
ok "Git initialized"
|
||||
fi
|
||||
|
||||
# --- Step 6: Git hooks ---
|
||||
if [ -d "$GIT_DIR" ]; then
|
||||
info "Installing git hooks..."
|
||||
bash "$FRAMEWORK_DIR/scripts/install-hooks.sh" "$PROJECT_DIR"
|
||||
fi
|
||||
|
||||
# --- Step 7: .gitignore ---
|
||||
GITIGNORE="$PROJECT_DIR/.gitignore"
|
||||
if [ -f "$GITIGNORE" ]; then
|
||||
if ! grep -q ".automaton/tasks/" "$GITIGNORE" 2>/dev/null; then
|
||||
echo "" >> "$GITIGNORE"
|
||||
echo "# Automaton" >> "$GITIGNORE"
|
||||
echo ".automaton/tasks/" >> "$GITIGNORE"
|
||||
echo ".automaton/loops/*/worktree/" >> "$GITIGNORE"
|
||||
warn "Added automaton entries to .gitignore"
|
||||
fi
|
||||
else
|
||||
cat > "$GITIGNORE" <<- 'EOF'
|
||||
# Automaton
|
||||
.automaton/tasks/
|
||||
.automaton/loops/*/worktree/
|
||||
.automaton/loops/*/outputs/
|
||||
EOF
|
||||
ok "Created .gitignore with automaton entries"
|
||||
fi
|
||||
|
||||
# --- Step 8: Verify ---
|
||||
info "Verifying setup..."
|
||||
cd "$FRAMEWORK_DIR"
|
||||
python3 "$FRAMEWORK_DIR/scripts/status.py" --project "$PROJECT_DIR" --audit 2>&1 | head -5 || true
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo -e "${GREEN} Onboarding complete!${NC}"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo " Project: $PROJECT_DIR"
|
||||
echo " Config: $CONFIG_FILE"
|
||||
echo " Models: $MODELS_FILE"
|
||||
echo ""
|
||||
echo " Next steps:"
|
||||
echo " 1. cd $PROJECT_DIR"
|
||||
echo " 2. Create a task:"
|
||||
echo " python3 ~/.automaton/scripts/status.py --create-task my-first-task --project ."
|
||||
echo " 3. Start working with your agent."
|
||||
echo ""
|
||||
Reference in New Issue
Block a user