Scripting Claude Code can be the most cost effective way to build automations on AI today. I use this when I need a set unit of defined work done in a parallel way but I can't use programatic means.
The best way to do this is by mimicking how Anthropic has designed this [for CI use cases](https://code.claude.com/docs/en/gitlab-ci-cd).
## Using Claude Code non-interactively
The core flag to switch to non-interactive mode is `-p`. This flag means that the response should be printed to stdout and Claude should exit immediately after taking it's desired actions.
```shell
claude -p "Instructions"
```
Now we get to add on the fun flags though to do a little bit more.
## Structured Output
I swear by structured output for so many use cases, and it's really easy to get this output from the tool.
```shell
curl https://simonwillison.net/guides/agentic-engineering-patterns/better-code/\#atom-everything | claude --print "I want to extract metadata about the site into structured json." --output-format=json --json-schema '{"type":"object","properties":{"title":{"type":"string"},"author":{"type":"string"},"publishedAt":{"type":"string"}},"required":["title","author","publishedAt"]}' | jq '.structured_output'
```
Which will return a result like the following:
```json
{
"title": "AI should help us produce better code",
"author": "Simon Willison",
"publishedAt": "2026-03-10"
}
```
## Tools & Permissions
If you know a workflow is going to need a specific tool to work you can give permission ahead of time with `--allowedTools` and it's complement:
- `--allowedTools, --allowed-tools <tools...>`
- `--disallowedTools, --disallowed-tools <tools...>`
This could be used if you have specific tools that need to be run in your workflow:
```shell
claude -p "Initialize this folder as a new repo and write a basic template readme for it. You should commit this as an initial commit." --allowedTools "Bash(git init *)" "Edit(/README.md)" "Bash(git add *)" "Bash(git commit *)"
```
However, most often I just end up wanting to give the agent a general "permission mode". This is set with `--permission-mode`:
```shell
claude --help | claude -p "Write a document called non-interactive-claude.md that exmplains how to use claude non-interactively." --permission-mode acceptEdits
```
| **Mode** | **File Edits** | **Bash Commands** |
| ---------------------- | --------------------------------------- | --------------------------------------- |
| plan | Blocked | Blocked |
| dontAsk | Blocked (unless using `--allowedTools`) | Blocked (unless using `--allowedTools`) |
| default | Prompts once per session | Prompts, can save approval |
| acceptEdits | Auto-approved | Prompts, can save approval |
| bypassPermissions/auto | Auto-approved | Auto-approved |
## Sessions
I am a regular user of `--continue` or `-c` for short. It get's me back into an existing session and is super useful. There's also the `--resume <session-id>` option that is most useful in multi turn scripting or building UI on top of Claude Code.
```shell
# Continue the most recent conversation
claude -p "what did we just discuss?" --continue
# Resume a specific session by ID
claude -p "follow up on that" --resume <session-uuid>
```
`--resume` is most often used with `--output-format=json` since the output contains the session id that is needed to resume.