Skip to main content
The then field in Pomo’s configuration allows you to run arbitrary commands when sessions complete. This enables powerful automation workflows beyond simple sound notifications.

Basic syntax

The then field accepts an array of commands. Each command is itself an array where:
  • First element: executable name or path
  • Remaining elements: command arguments
work:
  then:
    - [command1, arg1, arg2]
    - [command2, arg1]
All commands in the then array run in parallel as separate goroutines (see actions/actions.go:27-29).

Multiple commands example

You can chain multiple actions together:
work:
  duration: 25m
  then:
    # Play a sound
    - [paplay, ~/sounds/complete.wav]
    # Speak a message
    - [spd-say, "Work session complete"]
    # Log to a file
    - [sh, -c, "echo $(date): Work session completed >> ~/pomo.log"]

break:
  duration: 5m
  then:
    - [paplay, ~/sounds/break-over.wav]
    - [notify-send, "Pomo", "Break time is over!"]

Advanced use cases

Integration with external services

Send webhooks or API calls when sessions complete:
work:
  then:
    # Send a webhook to Zapier/IFTTT
    - [curl, -X, POST, "https://maker.ifttt.com/trigger/pomo_complete/with/key/YOUR_KEY"]
    
    # Post to Slack
    - [curl, -X, POST, "-H", "Content-Type: application/json", "-d", '{"text":"Completed a Pomodoro!"}', "YOUR_SLACK_WEBHOOK"]

Logging and analytics

Track your productivity automatically:
work:
  then:
    # Append to CSV log
    - [sh, -c, "echo $(date +%Y-%m-%d,%H:%M:%S),work,25 >> ~/productivity.csv"]
    
    # Update a counter file
    - [sh, -c, "expr $(cat ~/pomo_count.txt) + 1 > ~/pomo_count.txt"]

Smart home integration

Control IoT devices based on your work sessions:
work:
  then:
    # Turn on smart lights (using Home Assistant)
    - [curl, -X, POST, "-H", "Authorization: Bearer YOUR_TOKEN", "-H", "Content-Type: application/json", "-d", '{"entity_id":"light.desk"}', "http://homeassistant.local:8123/api/services/light/turn_on"]

break:
  then:
    # Dim the lights
    - [curl, -X, POST, "-H", "Authorization: Bearer YOUR_TOKEN", "-H", "Content-Type: application/json", "-d", '{"entity_id":"light.desk","brightness":100}', "http://homeassistant.local:8123/api/services/light/turn_on"]

Task management integration

Update your task tracker:
work:
  then:
    # Add time entry to Toggl
    - [python3, ~/scripts/toggl_track.py, "--duration", "25"]
    
    # Update Notion database
    - [node, ~/scripts/notion-update.js]

Custom scripts

Run your own automation scripts:
work:
  then:
    - [python3, ~/scripts/backup_notes.py]
    - [bash, ~/scripts/git_commit_work.sh]

break:
  then:
    - [python3, ~/scripts/stretch_reminder.py]

Execution model

Parallel execution

All commands run simultaneously in separate goroutines:
// From actions/actions.go:27-29
wg.Go(func() {
    runPostCommands(ctx, task.Then)
})
This means if you have multiple commands, they don’t wait for each other:
then:
  - [sleep, "3"]  # Starts immediately
  - [echo, "Hello"]  # Also starts immediately, doesn't wait for sleep

Command timeout

Each command has a 5-second timeout (defined in actions/actions.go:15). Commands exceeding this limit are automatically terminated.
var CommandTimeout = 5 * time.Second
For long-running tasks, consider:
  • Running them in the background with &
  • Using nohup to detach from the parent process
  • Triggering a background service instead of running directly

Context cancellation

Commands are cancelled when the next session starts:
// From actions/actions.go:69
c := exec.CommandContext(ctx, cmd[0], cmd[1:]...)
When you start a new session, the context is cancelled and all running commands receive a termination signal.

Error handling

If a command fails, Pomo logs the error but continues execution:
// From actions/actions.go:71-74
if err := c.Run(); err != nil {
    log.Printf("failed to run command '%q': %v\n", cmd, err)
}
Enable debug logging to see command execution details:
DEBUG=1 pomo 25m
Check debug.log for command output and errors.

Shell commands and pipes

To use shell features like pipes, redirects, or environment variables, invoke a shell:
work:
  then:
    # Use sh -c for shell features
    - [sh, -c, "echo 'Work done' | tee -a ~/pomo.log"]
    
    # Or bash for bash-specific features
    - [bash, -c, "source ~/.bashrc && my_custom_function"]
    
    # Windows: use PowerShell
    - [powershell, -Command, "Get-Date | Out-File -Append pomo.log"]

Best practices

1

Test commands manually first

Always test your commands in the terminal before adding them to config:
paplay ~/sounds/bell.wav
curl -X POST "https://api.example.com/webhook"
2

Keep commands fast

Remember the 5-second timeout. For longer tasks, trigger background processes:
then:
  - [sh, -c, "nohup ~/long-script.sh &"]
3

Handle errors gracefully

Use shell error handling if needed:
then:
  - [sh, -c, "command || echo 'Failed' >> ~/errors.log"]
4

Use absolute paths

Prefer absolute paths or ~/ for home directory:
# ✅ Good
- [python3, ~/scripts/my_script.py]

# ❌ Avoid
- [python3, scripts/my_script.py]

Troubleshooting

Ensure the executable is in your PATH or use absolute paths:
# Find the full path
which paplay
# Output: /usr/bin/paplay
Then use the full path:
then:
  - [/usr/bin/paplay, ~/sounds/bell.wav]
Enable debug logging to see what’s happening:
DEBUG=1 pomo 25m
Check debug.log in the current directory for detailed execution logs.
Common mistakes:
# ❌ Wrong - missing outer array
then: [echo, hello]

# ✅ Correct - array of command arrays
then:
  - [echo, hello]

# ❌ Wrong - string instead of array
then:
  - "echo hello"

# ✅ Correct - command array
then:
  - [echo, hello]

Build docs developers (and LLMs) love