|
Run recording Wraps terraform/tofu/terragrunt commands and captures output, timing, exit codes. |
Git and CI context Automatically records commit, branch, user, and CI provider info. |
|
Resource timeline Parses resource-level events and displays them as a gantt chart. |
S3 sync Optional S3 backend for sharing history across machines or teams. |
brew install Owloops/tap/tfjournalcurl -sSL https://raw.githubusercontent.com/Owloops/tfjournal/main/install.sh | bashgo install github.com/Owloops/tfjournal@latestgit clone https://github.com/Owloops/tfjournal.git
cd tfjournal
make build# Record a terraform run
tfjournal -- terraform apply
# Set workspace name manually
tfjournal -w prod -- tofu plan
# Works with terragrunt
tfjournal -- terragrunt apply
# Open TUI
tfjournal
# List runs
tfjournal list
tfjournal list --since 7d --status failed
tfjournal list --action apply
# Show run details
tfjournal show run_abc123
tfjournal show run_abc123 --outputalias tf='tfjournal -- terraform'
alias tofu='tfjournal -- tofu'
alias tg='tfjournal -- terragrunt'tfjournal serveOpens at http://localhost:8080. Same features as TUI with mouse support.
| Env var | Flag | Default | Description |
|---|---|---|---|
TFJOURNAL_PORT |
--port, -p |
8080 |
Port to listen on |
TFJOURNAL_BIND |
--bind, -b |
127.0.0.1 |
Address to bind to |
TFJOURNAL_USERNAME |
- | - | Basic auth username |
TFJOURNAL_PASSWORD |
- | - | Basic auth password |
Enable basic auth when exposing beyond localhost:
TFJOURNAL_USERNAME=admin TFJOURNAL_PASSWORD=secret tfjournal serve --bind 0.0.0.0export TFJOURNAL_S3_BUCKET=my-tfjournal
export TFJOURNAL_S3_REGION=us-east-1
export TFJOURNAL_S3_PREFIX=team-a # optional
export AWS_PROFILE=my-profile # optional, uses default credentials if not setWithout TFJOURNAL_S3_BUCKET, tfjournal uses local storage only.
Writes go to local storage first, then upload to S3 in the background. The TUI loads local runs immediately and fetches S3 runs in the background.
Share a single S3 bucket across teams using different prefixes:
# Team A
export TFJOURNAL_S3_PREFIX=team-a
# Team B
export TFJOURNAL_S3_PREFIX=team-bEach team sees only their runs. Filter by user with tfjournal list --user alice or search by username in TUI.
Each run records:
{
"id": "run_abc123",
"workspace": "production/alb",
"timestamp": "2025-01-23T10:30:00Z",
"duration_ms": 154000,
"status": "success",
"program": "terraform",
"user": "john",
"git": {
"commit": "abc123",
"branch": "main",
"dirty": false
},
"ci": {
"provider": "github-actions",
"actor": "john"
},
"changes": { "add": 2, "change": 0, "destroy": 0 },
"resources": [
{
"address": "aws_instance.web",
"action": "create",
"duration_ms": 30000
}
]
}~/.local/share/tfjournal/
├── runs/
│ └── run_abc123.json
└── outputs/
└── run_abc123.txt
Override with TFJOURNAL_STORAGE_PATH.
| Provider | Detection | Actor |
|---|---|---|
| GitHub Actions | GITHUB_ACTIONS=true |
GITHUB_ACTOR |
| GitLab CI | GITLAB_CI=true |
GITLAB_USER_LOGIN |
tfjournal list [workspace-pattern] [flags]
Flags:
--since string Filter by time (7d, 24h)
--user string Filter by user
--status string Filter by status (success, failed)
--program string Filter by program (terraform, tofu, terragrunt)
--action string Filter by action (plan, apply, destroy, import, taint)
--branch string Filter by git branch
--has-changes Only runs with actual changes
-n, --limit int Max runs (default: 20)
--json JSON outputtfjournal show <run-id> [flags]
Flags:
--output Show captured output
--json JSON outputNote
This project was built with assistance from LLMs. Human review and guidance provided where needed..

