Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: add preinstall/postinstall script + tools for goose and claude code #424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 43 commits into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
470ae43
use `goose` if in PATH
bpmct Apr 7, 2025
364d468
feat(goose): add pre and post install script variables for customization
bpmct Apr 7, 2025
b7cc2f2
refactor(goose): improve handling of pre and post install scripts wit…
bpmct Apr 7, 2025
45b21e1
fix
bpmct Apr 7, 2025
220a026
fix
bpmct Apr 7, 2025
e8ef8f5
debug
bpmct Apr 7, 2025
5744f7a
fix
bpmct Apr 7, 2025
467ad91
cleanup
bpmct Apr 7, 2025
eaceba4
fixup
bpmct Apr 8, 2025
e2cb2fa
fixup
bpmct Apr 8, 2025
d9a7275
ok
bpmct Apr 8, 2025
55073da
add debug
bpmct Apr 8, 2025
3ccd98c
debug
bpmct Apr 8, 2025
d2ca53b
fix handling
bpmct Apr 8, 2025
c1e83e0
fixes
bpmct Apr 8, 2025
92fb309
cleanup
bpmct Apr 8, 2025
9865dec
fix path bs
bpmct Apr 8, 2025
324508e
fix
bpmct Apr 8, 2025
a025219
fix
bpmct Apr 8, 2025
928abda
fix escaping
bpmct Apr 8, 2025
bf41bb2
ok
bpmct Apr 8, 2025
19bda0d
fix
bpmct Apr 8, 2025
a50cb4b
fixup
bpmct Apr 8, 2025
abdbe1f
remove
bpmct Apr 8, 2025
4445af8
no prompt
bpmct Apr 8, 2025
04b9686
always reattach
bpmct Apr 8, 2025
4189f04
fix
bpmct Apr 8, 2025
2709f2a
Merge remote-tracking branch 'origin' into updates
bpmct Apr 8, 2025
e980d9c
fix system prompt
bpmct Apr 8, 2025
7634bd7
fix
bpmct Apr 8, 2025
81ad454
add support for additional extensions
bpmct Apr 9, 2025
2c7e9e9
fix
bpmct Apr 9, 2025
7f836ff
test
bpmct Apr 9, 2025
3542350
even clearer
bpmct Apr 9, 2025
3bf9e0f
fix
bpmct Apr 9, 2025
438c30f
fix again
bpmct Apr 9, 2025
20b1fca
fix
bpmct Apr 9, 2025
77bca7b
feat: add pre/post install for goose + custom extensions
bpmct Apr 9, 2025
d4ffca0
fmt
Apr 16, 2025
1f9d7ea
feat: add pre and post install script variables for Claude Code
Apr 16, 2025
b369d72
postinstallbetter
Apr 16, 2025
d31daad
test
Apr 16, 2025
7a1b282
base64 encode scripts
Apr 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions claude-code/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,23 @@ variable "experiment_report_tasks" {
default = false
}

variable "experiment_pre_install_script" {
type = string
description = "Custom script to run before installing Claude Code."
default = null
}

variable "experiment_post_install_script" {
type = string
description = "Custom script to run after installing Claude Code."
default = null
}

locals {
encoded_pre_install_script = var.experiment_pre_install_script != null ? base64encode(var.experiment_pre_install_script) : ""
encoded_post_install_script = var.experiment_post_install_script != null ? base64encode(var.experiment_post_install_script) : ""
}

# Install and Initialize Claude Code
resource "coder_script" "claude_code" {
agent_id = var.agent_id
Expand All @@ -74,6 +91,14 @@ resource "coder_script" "claude_code" {
command -v "$1" >/dev/null 2>&1
}

# Run pre-install script if provided
if [ -n "${local.encoded_pre_install_script}" ]; then
echo "Running pre-install script..."
echo "${local.encoded_pre_install_script}" | base64 -d > /tmp/pre_install.sh
chmod +x /tmp/pre_install.sh
/tmp/pre_install.sh
fi

# Install Claude Code if enabled
if [ "${var.install_claude_code}" = "true" ]; then
if ! command_exists npm; then
Expand All @@ -84,6 +109,14 @@ resource "coder_script" "claude_code" {
npm install -g @anthropic-ai/claude-code@${var.claude_code_version}
fi

# Run post-install script if provided
if [ -n "${local.encoded_post_install_script}" ]; then
echo "Running post-install script..."
echo "${local.encoded_post_install_script}" | base64 -d > /tmp/post_install.sh
chmod +x /tmp/post_install.sh
/tmp/post_install.sh
fi

if [ "${var.experiment_report_tasks}" = "true" ]; then
echo "Configuring Claude Code to report tasks via Coder MCP..."
coder exp mcp configure claude-code ${var.folder}
Expand Down
30 changes: 30 additions & 0 deletions goose/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,36 @@ module "goose" {
}
```

### Adding Custom Extensions (MCP)

You can extend Goose's capabilities by adding custom extensions. For example, to add the desktop-commander extension:

```tf
module "goose" {
# ... other configuration ...

experiment_pre_install_script = <<-EOT
npm i -g @wonderwhy-er/desktop-commander@latest
EOT

experiment_additional_extensions = <<-EOT
desktop-commander:
args: []
cmd: desktop-commander
description: Ideal for background tasks
enabled: true
envs: {}
name: desktop-commander
timeout: 300
type: stdio
EOT
}
```

This will add the desktop-commander extension to Goose, allowing it to run commands in the background. The extension will be available in the Goose interface and can be used to run long-running processes like development servers.

Note: The indentation in the heredoc is preserved, so you can write the YAML naturally.

## Run standalone

Run Goose as a standalone app in your workspace. This will install Goose and run it directly without using screen or any task reporting to the Coder UI.
Expand Down
150 changes: 116 additions & 34 deletions goose/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,60 @@ variable "experiment_goose_model" {
default = null
}

variable "experiment_pre_install_script" {
type = string
description = "Custom script to run before installing Goose."
default = null
}

variable "experiment_post_install_script" {
type = string
description = "Custom script to run after installing Goose."
default = null
}

variable "experiment_additional_extensions" {
type = string
description = "Additional extensions configuration in YAML format to append to the config."
default = null
}

locals {
base_extensions = <<-EOT
coder:
args:
- exp
- mcp
- server
cmd: coder
description: Report ALL tasks and statuses (in progress, done, failed) you are working on.
enabled: true
envs:
CODER_MCP_APP_STATUS_SLUG: goose
name: Coder
timeout: 3000
type: stdio
developer:
display_name: Developer
enabled: true
name: developer
timeout: 300
type: builtin
EOT

# Add two spaces to each line of extensions to match YAML structure
formatted_base = " ${replace(trimspace(local.base_extensions), "\n", "\n ")}"
additional_extensions = var.experiment_additional_extensions != null ? "\n ${replace(trimspace(var.experiment_additional_extensions), "\n", "\n ")}" : ""

combined_extensions = <<-EOT
extensions:
${local.formatted_base}${local.additional_extensions}
EOT

encoded_pre_install_script = var.experiment_pre_install_script != null ? base64encode(var.experiment_pre_install_script) : ""
encoded_post_install_script = var.experiment_post_install_script != null ? base64encode(var.experiment_post_install_script) : ""
}

# Install and Initialize Goose
resource "coder_script" "goose" {
agent_id = var.agent_id
Expand All @@ -92,6 +146,14 @@ resource "coder_script" "goose" {
command -v "$1" >/dev/null 2>&1
}

# Run pre-install script if provided
if [ -n "${local.encoded_pre_install_script}" ]; then
echo "Running pre-install script..."
echo "${local.encoded_pre_install_script}" | base64 -d > /tmp/pre_install.sh
chmod +x /tmp/pre_install.sh
/tmp/pre_install.sh
fi

# Install Goose if enabled
if [ "${var.install_goose}" = "true" ]; then
if ! command_exists npm; then
Expand All @@ -102,36 +164,29 @@ resource "coder_script" "goose" {
RELEASE_TAG=v${var.goose_version} curl -fsSL https://github.com/block/goose/releases/download/stable/download_cli.sh | CONFIGURE=false bash
fi

# Run post-install script if provided
if [ -n "${local.encoded_post_install_script}" ]; then
echo "Running post-install script..."
echo "${local.encoded_post_install_script}" | base64 -d > /tmp/post_install.sh
chmod +x /tmp/post_install.sh
/tmp/post_install.sh
fi

# Configure Goose if auto-configure is enabled
if [ "${var.experiment_auto_configure}" = "true" ]; then
echo "Configuring Goose..."
mkdir -p "$HOME/.config/goose"
cat > "$HOME/.config/goose/config.yaml" << EOL
GOOSE_PROVIDER: ${var.experiment_goose_provider}
GOOSE_MODEL: ${var.experiment_goose_model}
extensions:
coder:
args:
- exp
- mcp
- server
cmd: coder
description: Report ALL tasks and statuses (in progress, done, failed) before and after starting
enabled: true
envs:
CODER_MCP_APP_STATUS_SLUG: goose
name: Coder
timeout: 3000
type: stdio
developer:
display_name: Developer
enabled: true
name: developer
timeout: 300
type: builtin
${trimspace(local.combined_extensions)}
EOL
fi

# Write system prompt to config
mkdir -p "$HOME/.config/goose"
echo "$GOOSE_SYSTEM_PROMPT" > "$HOME/.config/goose/.goosehints"

# Run with screen if enabled
if [ "${var.experiment_use_screen}" = "true" ]; then
echo "Running Goose in the background..."
Expand Down Expand Up @@ -162,14 +217,28 @@ EOL
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

screen -U -dmS goose bash -c '
# Determine goose command
if command_exists goose; then
GOOSE_CMD=goose
elif [ -f "$HOME/.local/bin/goose" ]; then
GOOSE_CMD="$HOME/.local/bin/goose"
else
echo "Error: Goose is not installed. Please enable install_goose or install it manually."
exit 1
fi

screen -U -dmS goose bash -c "
cd ${var.folder}
$HOME/.local/bin/goose run --text "$GOOSE_SYSTEM_PROMPT. Your task: $GOOSE_TASK_PROMPT" --interactive | tee -a "$HOME/.goose.log"
exec bash
'
\"$GOOSE_CMD\" run --text \"Review your goosehints. Every step of the way, report tasks to Coder with proper descriptions and statuses. Your task at hand: $GOOSE_TASK_PROMPT\" --interactive | tee -a \"$HOME/.goose.log\"
/bin/bash
"
else
# Check if goose is installed before running
if ! command_exists $HOME/.local/bin/goose; then
if command_exists goose; then
GOOSE_CMD=goose
elif [ -f "$HOME/.local/bin/goose" ]; then
GOOSE_CMD="$HOME/.local/bin/goose"
else
echo "Error: Goose is not installed. Please enable install_goose or install it manually."
exit 1
fi
Expand All @@ -186,21 +255,34 @@ resource "coder_app" "goose" {
#!/bin/bash
set -e

# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}

# Determine goose command
if command_exists goose; then
GOOSE_CMD=goose
elif [ -f "$HOME/.local/bin/goose" ]; then
GOOSE_CMD="$HOME/.local/bin/goose"
else
echo "Error: Goose is not installed. Please enable install_goose or install it manually."
exit 1
fi

if [ "${var.experiment_use_screen}" = "true" ]; then
if screen -list | grep -q "goose"; then
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
echo "Attaching to existing Goose session." | tee -a "$HOME/.goose.log"
screen -xRR goose
else
echo "Starting a new Goose session." | tee -a "$HOME/.goose.log"
screen -S goose bash -c 'export LANG=en_US.UTF-8; export LC_ALL=en_US.UTF-8; $HOME/.local/bin/goose run --text "Always report status and instructions to Coder, before and after your steps" --interactive | tee -a "$HOME/.goose.log"; exec bash'
# Check if session exists first
if ! screen -list | grep -q "goose"; then
echo "Error: No existing Goose session found. Please wait for the script to start it."
exit 1
fi
# Only attach to existing session
screen -xRR goose
else
cd ${var.folder}
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
$HOME/.local/bin/goose
"$GOOSE_CMD" run --text "Review goosehints. Your task: $GOOSE_TASK_PROMPT" --interactive
fi
EOT
icon = var.icon
Expand Down