DEV Community

yureki_lab
yureki_lab

Posted on

5 Claude Code CLI Tricks I Wish I'd Known From Day One

TL;DR

I spent about four months using Claude Code as my daily driver before I stumbled onto the handful of CLI features that actually change how you work with it. None of these are secret — they're all in the docs — but I didn't internalize them until I'd already wasted dozens of hours doing things the slow way. Here are the five that made the biggest difference: headless mode, custom slash commands, permission allowlists, session resume, and per-task model selection.

The Problem

When I first started using Claude Code, I treated it like a fancier autocomplete: open a terminal, type a prompt, watch it work, close the terminal, repeat tomorrow. That's a completely reasonable way to start, but it leaves a lot of value on the table.

Three specific pains kept showing up:

  1. Repetitive prompts. I was retyping the same multi-paragraph instructions for recurring tasks — "review this diff for X, Y, Z" — every single time, because I didn't know there was a better way to save them.
  2. Permission fatigue. Every git status, every npm test, every ls triggered a confirmation prompt. By hour two of a session I was just mashing "yes" without reading what I was approving, which defeats the entire point of having a confirmation step.
  3. Losing context between sessions. If I closed my laptop mid-refactor, I'd come back the next day and either re-explain the whole plan from scratch or just start over.

None of these are exotic problems. They're the kind of friction that's easy to shrug off as "just how it is" — until you find out it isn't.

How I Solved It

Here's roughly how the five habits fit together in a normal week now:

flowchart LR
    A[Recurring task] --> B{Interactive or scripted?}
    B -->|Scripted / CI| C[Headless mode: claude -p]
    B -->|Interactive, repeatable| D[Custom slash command]
    C --> E[Permission allowlist in settings.json]
    D --> E
    E --> F[Long task spans multiple days]
    F --> G[Resume session with --continue/--resume]
    D --> H[Pick model/effort per task]
    C --> H
Enter fullscreen mode Exit fullscreen mode

1. Headless mode for anything that doesn't need a human in the loop

Claude Code has a non-interactive mode: claude -p "<prompt>". It runs once, prints the result, and exits — no REPL, no back-and-forth. That makes it trivially easy to wire into a shell script, a Makefile target, or a CI step.

# Summarize the diff of the last commit and print it as plain text
claude -p "Summarize the changes in the most recent git commit in 3 bullet points. No preamble."

# Use it inside a script
diff_summary=$(claude -p "Read the staged diff via 'git diff --cached' and flag anything that looks like a breaking API change.")
echo "$diff_summary"
Enter fullscreen mode Exit fullscreen mode

I use this for things like: generating a first-pass changelog entry from a commit range, triaging a batch of GitHub issues into rough priority buckets, or running a "does this PR touch anything security-sensitive" check before I even open the diff myself. None of these need me watching the terminal — they need an answer I can read later.

The trick I missed for weeks: you can pass --output-format json to headless mode and get structured output back, which means you can pipe the result straight into jq or another script instead of scraping plain text.

2. Custom slash commands for anything that does need a human in the loop

For tasks I run interactively and repeatedly, I stopped retyping prompts and started saving them as slash commands. Drop a markdown file in .claude/commands/, and it becomes a /command-name you can invoke inside any session.

<!-- .claude/commands/triage.md -->
Triage the currently open GitHub issues for this repo.

For each issue:
- Classify as bug / feature / question / stale
- Flag anything that looks like a duplicate of another open issue
- Suggest a priority: P0 (blocking), P1 (soon), P2 (backlog)

Output as a markdown table. Don't comment on the issues yet, just report.
Enter fullscreen mode Exit fullscreen mode

Now /triage does the same job every time, with the same structure, and I can hand it off to a teammate without re-explaining the prompt in Slack. The bigger unlock was realizing these commands can take arguments ($ARGUMENTS in the file body gets substituted with whatever you type after the command name), so one file can cover a whole family of related tasks instead of needing a dozen near-duplicate commands.

3. Permission allowlists so "yes" means something again

This was the single biggest quality-of-life change. In .claude/settings.json (or the user-level ~/.claude/settings.json), you can allowlist specific tool calls so Claude Code stops asking for things that are obviously safe in your workflow:

{
  "permissions": {
    "allow": [
      "Bash(git status)",
      "Bash(git diff*)",
      "Bash(npm test)",
      "Bash(npm run lint)",
      "Read(*)"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Read-only commands and test runs don't need a confirmation dialog every time — they can't destroy anything. Once I trimmed the prompt volume down to "things that actually matter" (deletes, force-pushes, writes outside the repo), I started reading every confirmation again instead of reflexively clicking through them. Permission fatigue isn't just annoying, it's a real safety regression, because it trains you to stop paying attention right when you need to be paying the most attention.

The part I got wrong the first time: I allowlisted too broadly, using a blanket Bash(*) entry because I was tired of the prompts. That's the wrong lesson to take from this. The point isn't "make the prompts go away," it's "make the prompts meaningful again" by only silencing the ones you'd approve on autopilot anyway. Scope each allow entry to a specific command, not a wildcard, and revisit the list every so often — it's easy to allowlist something once for a one-off task and forget it's still sitting there six months later.

4. Session resume for anything that spans more than one sitting

claude --continue picks up your most recent conversation in the current directory. claude --resume gives you a picker across recent sessions if you need to jump back into something from a few days ago. Either way, the full context — what you asked for, what Claude already tried, what it learned about the codebase along the way — comes back with it.

# Pick up right where you left off yesterday
claude --continue

# Or choose from a list of recent sessions
claude --resume
Enter fullscreen mode Exit fullscreen mode

Before I found this, "close laptop mid-task" meant "lose the plan." Now a multi-day refactor is just... a multi-day refactor, not five separate one-day refactors that don't quite agree with each other.

5. Matching model and effort to the actual task

Not every task deserves the same amount of reasoning. A one-line lint fix and "redesign this module's error handling" are not the same job, and treating them the same wastes either time or quality. Claude Code lets you set the model and reasoning effort per invocation instead of locking a whole session to one setting:

# Fast, cheap pass for a mechanical fix
claude -p "Fix the unused-import lint errors in src/utils/format.ts" --model haiku

# Slower, deeper pass for something that needs actual judgment
claude -p "Propose two different approaches to add retry logic to the API client, with tradeoffs" --model opus
Enter fullscreen mode Exit fullscreen mode

I used to run everything on one model out of habit. Splitting mechanical work from judgment-call work cut my average wait time noticeably, without touching the quality of the harder tasks at all — because the harder tasks were still getting the deeper model.

Lessons Learned

  1. The interactive REPL is the least automatable part of Claude Code, not the whole product. Headless mode is where most of the leverage lives once you're past the "getting a feel for it" phase.
  2. Permission fatigue is a security problem disguised as an annoyance. If you're clicking "yes" without reading the prompt, your confirmation step isn't protecting you from anything.
  3. Slash commands are cheaper to write than you think, and pay for themselves after the second use. I was mentally filing this under "nice to have someday" when it should've been week-one setup.
  4. Context loss between sessions is avoidable, not inherent. I spent months assuming "start fresh tomorrow" was just the cost of doing business.
  5. Model choice is a per-task decision, not a per-session one. The biggest mistake was treating "which model" like a global setting instead of a parameter you tune per prompt.

What's Next

I'm still underusing hooks (the ability to run a script automatically before/after specific tool calls) — that's the next thing on my list to actually sit down and configure properly instead of half-reading the docs and moving on. I also want to get more disciplined about writing slash commands before I need them a third time, instead of my current habit of retyping a prompt twice, sighing, and only then saving it as a command. If either of those turns into something worth writing up on its own, it'll be the next post.

Wrap-up

If you're running Claude Code purely as an interactive REPL right now, try headless mode on one recurring task this week — it's a five-minute change that keeps paying off. And if you've found a CLI trick that's saved you real time, I'd genuinely like to hear about it — drop it in the comments.

If this was useful, follow me here on Dev.to — I write about building and operating AI coding agents on a regular cadence.

Top comments (0)