Provisioning Scripts
Provisioning ensures that files and directories are in the desired state when a space starts or on demand. Knot provides the scriptling.provision.file library for writing idempotent provisioning scripts that only make changes when needed.
How Provisioning Works
A provisioning script uses scriptling.provision.file to declare the desired state of files and directories inside a space. The library is idempotent – it compares the current state against the desired state and only writes when content or permissions differ.
There are three ways to run a provisioning script:
| Method | Scope | When It Runs |
|---|---|---|
| Template startup script | All spaces from the template | Automatically on space start |
| User startup script | Individual space | Automatically on space start (after template script) |
| Manual execution | Individual space | On demand via CLI |
Writing a Provisioning Script
Provisioning scripts use the scriptling.provision.file library, available in the Remote and External environments:
import scriptling.provision.file as file
file.ensure("~/.bashrc", """export PATH="$HOME/bin:$PATH"
export EDITOR=vim
alias ll='ls -la'
""")
file.ensure_directory("~/bin", mode=0o755)
file.ensure("~/bin/setup.sh", """#!/bin/bash
echo "Environment ready"
""", mode=0o755)Each call to ensure returns a status constant (file.CREATED, file.UPDATED, or file.UNCHANGED) so you can log results:
import scriptling.provision.file as file
status = file.ensure("~/.gitconfig", """[user]
name = Jane Doe
email = [email protected]
""", mode=0o600)
if status == file.CREATED:
print("Created .gitconfig")
elif status == file.UPDATED:
print("Updated .gitconfig")See the scriptling.provision.file reference for the full API including absent, ensure_directory, and absent_directory.
Running a Provisioning Script
As a Template Startup Script
Setting a provisioning script as the System Startup Script in a template ensures every space created from that template is provisioned on start.
- Create your provisioning script under Scripts
- Edit the template and select the script as the System Startup Script
This runs first in the execution order, before user startup scripts and file-based scripts.
As a User Startup Script
Individual users can set a provisioning script for their own space via the web interface:
- Navigate to the space settings
- Select Startup Script
- Choose a provisioning script to run on startup
This runs after the template startup script.
On Demand
Run a provisioning script in a running space at any time:
knot space run-script myspace provision-environmentThis is useful for re-applying configuration after manual changes, or for one-time setup tasks.
Example: Development Environment
A provisioning script that sets up a complete development environment:
import scriptling.provision.file as file
file.ensure("~/.bashrc", """# ~/.bashrc
export PATH="$HOME/.local/bin:$PATH"
export EDITOR=nano
alias ll='ls -alF'
alias gs='git status'
""")
file.ensure_directory("~/.config/git")
file.ensure("~/.config/git/ignore", """*.swp
*.swo
*~
.DS_Store
""")
file.ensure_directory("~/projects", mode=0o755)
file.ensure("~/projects/README.md", """# Projects
This directory contains project workspaces.
""")Example: Service Configuration
Provision configuration files for services running in the space:
import scriptling.provision.file as file
import knot.vars as vars
db_host = vars.get("DB_HOST")["value"]
db_port = vars.get("DB_PORT")["value"]
file.ensure("/etc/myapp/config.yaml", f"""database:
host: {db_host}
port: {db_port}
name: myapp
server:
host: 0.0.0.0
port: 8080
""", mode=0o640)
file.ensure_directory("/var/log/myapp", mode=0o755)
file.ensure("/etc/myapp/healthcheck.sh", """#!/bin/bash
curl -sf http://localhost:8080/health || exit 1
""", mode=0o755)Combining with Variables
Provisioning scripts can read variables to adapt configuration per space or environment:
import scriptling.provision.file as file
import knot.vars as vars
env = vars.get("ENVIRONMENT")["value"] or "development"
if env == "production":
file.ensure("~/.config/app/settings.toml", """[server]
workers = 4
debug = false
""")
else:
file.ensure("~/.config/app/settings.toml", """[server]
workers = 1
debug = true
""")Best Practices
- Keep scripts idempotent:
scriptling.provision.fileis idempotent by design – use it instead of shell commands for file operations - Use template-level for shared config: Set provisioning as the template startup script for configuration common to all spaces
- Use user-level for personalization: Let users set their own provisioning script for individual customizations
- Log changes: Check return values to log what was created or updated
- Use variables for per-space config: Read variables to make provisioning scripts adapt to different environments
What’s Next
- scriptling.provision.file Reference - Full API documentation
- Startup & Shutdown Scripts - Script execution lifecycle
- Variables - Per-space and global configuration
- Script Examples - More scriptling examples