Stage 1 · Code
Your First Real Program
CLI Project Plan
Design a task tracker CLI from scratch — define commands, flags, data shapes, and the package structure before writing a line of code.
What We Are Building
Over the next six lessons we will build tasker — a command-line task tracker. It will store tasks as JSON, support adding, listing, completing, and deleting tasks, and ship as a single static binary.
Command-line tools are the perfect beginner project: they exercise reading input, parsing flags, working with files, handling errors, and producing clean output — all without the complexity of a network server or a UI framework. Every SRE tool you will build professionally is a CLI.
Commands and Flags
A well-designed CLI has a consistent command structure. Subcommands group related operations; flags modify their behaviour. The UNIX convention is tool verb [flags] [arguments].
| Command | Flags | Effect |
|---|---|---|
tasker add | -title "Buy milk" -tag shopping | Create a new task |
tasker list | -tag shopping -done false | List tasks, optionally filtered |
tasker done | -id <id> | Mark a task complete |
tasker delete | -id <id> | Remove a task |
tasker help | — | Print usage information |
Data Shape
Define the data shape before writing any code. This forces you to think about what information you actually need and what the JSON storage will look like.
Package Structure
A small but real project layout: cmd/tasker holds main.go; internal/task holds the data model and storage logic; internal/cli handles command parsing.
mkdir -p tasker/cmd/tasker
mkdir -p tasker/internal/task
mkdir -p tasker/internal/cli
cd tasker
go mod init github.com/thesyscoder/tasker
# Result:
# tasker/
# cmd/tasker/main.go ← entry point
# internal/task/task.go ← data model
# internal/task/store.go ← file-based storage
# internal/cli/commands.go ← command handlers
# go.modThe internal/ prefix restricts imports to this module only. Splitting task (data) from cli (presentation) follows the separation-of-concerns principle and makes each part independently testable.
cmd/tasker/main.go— parses the subcommand and delegates tocli.internal/task/task.go— definesTaskandTaskstypes.internal/task/store.go— reads and writestasks.jsonwith proper locking.internal/cli/commands.go— one function per subcommand:Add,List,Done,Delete.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.