Quick reference for building and testing Construct CLI during development.
# Clone and build
git clone https://github.com/EstebanForge/construct-cli.git
cd construct-cli
make build
# Run tests
make testConstruct provides three installation methods for local testing:
Fastest method for development - installs to ~/.local/bin without sudo or confirmations.
# Quick install (no sudo needed)
make install-dev
# Or directly:
./scripts/dev-install.sh
# Verify
construct --versionPros:
- ⚡ Very fast (no confirmations)
- 🔓 No sudo required
- ✨ Perfect for rapid iteration
Cons:
- No backup of existing binary
- Requires
~/.local/binin your PATH - On macOS, use
make build-signed && cp bin/construct ~/.local/bin/constructif the binary is killed on launch (Gatekeeper / Code Signing subsystem error). If already copied, re-sign in place:codesign -s - -f ~/.local/bin/construct && construct sys version
Full-featured install with backup, verification, and safety checks.
# Install to ~/.local/bin (default, no sudo)
make install-local
# Or install to system directory (requires sudo)
sudo INSTALL_DIR=/usr/local/bin make install-local
# With options
./scripts/install-local.sh --help
./scripts/install-local.sh --clean # Clean build first
./scripts/install-local.sh --no-backup # Skip backup
./scripts/install-local.sh --skip-build # Use existing binary
# Install to system directory with options
sudo INSTALL_DIR=/usr/local/bin ./scripts/install-local.sh --cleanPros:
- 💾 Automatic backup of existing binary
- ✅ Full verification
- 📋 Detailed output
- 🔓 No sudo needed (default)
Use cases:
- Testing before committing changes
- Comparing versions
- Need to rollback easily
Simple install without bells and whistles.
make install# Basic uninstall from ~/.local/bin (no sudo)
make uninstall-local
# List available backups
./scripts/uninstall-local.sh --list-backups
# Restore previous version
./scripts/uninstall-local.sh --restore
# Force removal without confirmation
./scripts/uninstall-local.sh --force
# Uninstall from system directory (requires sudo)
sudo INSTALL_DIR=/usr/local/bin ./scripts/uninstall-local.sh# Make changes to code
vim internal/agent/runner.go
# Quick test
make install-dev
construct sys doctor
# If something broke, check backups
./scripts/uninstall-local.sh --list-backups
# Restore previous working version
./scripts/uninstall-local.sh --restore
# If you installed to /usr/local/bin:
sudo INSTALL_DIR=/usr/local/bin ./scripts/uninstall-local.sh --restore# Full testing before committing
make clean # Clean old builds
make fmt # go fmt (+ goimports if installed)
make vet # go vet
make lint # golangci-lint
make test-unit # Unit tests
make install-local # Install with backup
construct sys doctor # Smoke test
make test-integration # Integration tests# Basic build
make build
# macOS: build + ad-hoc sign (required to avoid "killed" on Apple Silicon / Gatekeeper)
make build-signed
# Build with all tests
make clean test
# Cross-compile for all platforms
make cross-compile
# Create release build
make release
# Development mode (build + init)
make dev# Run all tests
make test
# Unit tests only
make test-unit
# Integration tests only
make test-integration
# With coverage report
make test-coverage
open coverage.html
# Run benchmarks
make bench
# Full local verification (fmt, vet, lint, test, build)
make check
# CI alias (same as make check)
make ci# Clean build artifacts only
make clean
# Clean Docker resources (containers, volumes, images)
make clean-docker
# Clean everything (build + Docker + config)
make clean-allDifferent install locations and when to use them:
| Directory | Sudo? | Default? | When to use |
|---|---|---|---|
~/.local/bin |
❌ | ✅ | User-local, development (default) |
/usr/local/bin |
✅ | ❌ | System-wide install, production |
~/bin |
❌ | ❌ | Alternative user directory |
/opt/construct |
✅ | ❌ | Isolated installation |
Set with environment variable:
# Install to custom location
INSTALL_DIR=~/bin make install-local
# Install to system directory
sudo INSTALL_DIR=/usr/local/bin make install-localIf binaries aren't found, add installation directory to PATH:
# For ~/.local/bin (add to ~/.bashrc or ~/.zshrc)
export PATH="$HOME/.local/bin:$PATH"
# For ~/bin
export PATH="$HOME/bin:$PATH"
# Reload shell
source ~/.bashrc # or source ~/.zshrc# Check if installed
which construct
# Check PATH
echo $PATH
# If not in PATH, add it
export PATH="$HOME/.local/bin:$PATH"# If installing to /usr/local/bin
sudo INSTALL_DIR=/usr/local/bin make install-local
# Or use user directory
INSTALL_DIR=~/.local/bin make install-dev# Check all installed versions
which -a construct
# Remove old versions
sudo rm /usr/local/bin/construct
rm ~/.local/bin/construct
# Reinstall
make install-dev# Clean everything and retry
make clean-all
make build
make test
# Check Docker
docker ps
docker images | grep construct
# Check config
cat ~/.config/construct-cli/config.tomlOn Linux, Construct propagates host identity for compose startup and exec paths to prevent ownership drift in mounted config/home paths.
# See current mapping/doctor details
construct sys doctor- If your host UID is not present in container
/etc/passwd, Construct warns, keeps numericUID:GIDmapping, and forcesHOME=/home/construct. - If migrations or runtime prep hit ownership issues, Construct prompts for confirmation and then attempts runtime-aware repair (
podman unshare chownfor rootless/userns modes when applicable, then sudo fallback). - For recurring Linux permission/ownership issues, use:
construct sys doctor --fixdoctor --fixcan repair config ownership/permissions, recycle stale session/daemon containers, and rebuild stale/missing images required for startup fixes.- If automated repair is declined or fails, use:
podman unshare chown -R 0:0 ~/.config/construct-cli
sudo chown -R "$(id -u)":"$(id -g)" ~/.config/construct-cliconstruct --ct-verbose sys shell
construct --ct-debug claude "test"construct --version
construct sys doctor# Build logs
cat ~/.config/construct-cli/logs/build_*.log
# Package install logs
cat ~/.config/construct-cli/logs/install_packages_*.log
# Update logs
cat ~/.config/construct-cli/logs/update_*.logmake depsmake fmtmake lintmake release
ls -lh dist/# Stable release example
# 1) set Version in internal/constants/constants.go to 1.3.8
# 2) tag and push
git tag 1.3.8
git push origin main --tags
# Beta release example
# 1) set Version in internal/constants/constants.go to 1.3.9-beta.1
# 2) tag and push
git tag 1.3.9-beta.1
git push origin main --tags- Do not manually edit
VERSIONorVERSION-BETA; release workflow updates them. - Stable tags update
VERSION. - Prerelease tags (contain
-, e.g.1.3.9-beta.1) updateVERSION-BETA. internal/constants/constants.gomust match the exact tag string formake releaseto pass.
# Create feature branch
git checkout -b feature/clipboard-support
# Make changes and test
make install-dev
construct sys doctor
# Run full test suite
make ci
# Commit
git add .
git commit -m "Add clipboard support"
# Push
git push origin feature/clipboard-support- Use
install-devduring active development - fastest iteration cycle - Use
install-localbefore committing - full verification with backup - Always run
make cibefore pushing - catches issues early - Keep backups -
install-localautomatically creates timestamped backups - Check logs - build and install logs are in
~/.config/construct-cli/logs/
Add to .vscode/tasks.json:
{
"version": "2.0.0",
"tasks": [
{
"label": "Build",
"type": "shell",
"command": "make build",
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "Test",
"type": "shell",
"command": "make test"
},
{
"label": "Install Dev",
"type": "shell",
"command": "make install-dev"
}
]
}All Makefile targets with descriptions:
make helpOutput:
Construct CLI - Build System
Usage: make [target]
Targets:
help Show this help message
build Build the binary
test Run all tests
test-unit Run Go unit tests
test-integration Run integration tests
install-local Install with backup and verification
install-dev Quick dev install (no sudo)
uninstall-local Uninstall with backup options
clean Clean build artifacts
...