How It Works
A plain text file becomes a real program. Here's how.
Start with a text file
You write what you want in your own words. That's the whole program. No syntax, no imports, no boilerplate.
Figure out where I am and tell me the current
weather conditions. If arguments are passed in,
it could be a zip code or city. If not, try to
geolocate.
You can cache the results for an hour so you
don't have to make a new request every time.
Run it directly with think:
$ think weather.txt "San Francisco"
San Francisco, CA
62°F, partly cloudy. Wind: 12 mph W. Humidity: 68%.
Build it
thought build turns your text file into a proper executable. It adds a shebang line and sets the file permissions so your system knows how to run it.
What's a shebang?
That first line, #!/usr/bin/env think, tells your computer which program should interpret this file. It's the same trick that Bash, Python, and Perl scripts have used for decades.
#!/usr/bin/env think
Figure out where I am and tell me the current
weather conditions. If arguments are passed in,
it could be a zip code or city. If not, try to
geolocate.
You can cache the results for an hour so you
don't have to make a new request every time.
$ thought build weather.txt -o weather
Built → ./weather (chmod +x)
$ ./weather "NYC"
New York, NY
45°F, clear skies. Wind: 8 mph NW. Humidity: 52%.
Before: a text file you run with think. After: a standalone executable you can hand to someone else.
Install it
thought install builds your script and puts it on your $PATH. It strips the extension and moves it to ~/.thinkingscript/bin/. Now it's just a command.
$ thought install weather.txt
Installed → ~/.thinkingscript/bin/weather
$ weather "New York"
New York, NY
45°F, clear skies. Wind: 8 mph NW. Humidity: 52%.
No wrapper scripts, no aliases. It's a real program that lives alongside grep, curl, and everything else in your terminal.
Managing installed thoughts
Once installed, you can manage your thoughts with the thought command.
$ thought ls
weather
news
stocks
$ thought info weather
Name: weather
Binary: ~/.thinkingscript/bin/weather (2.1 KB)
Workspace: ~/.thinkingscript/thoughts/weather/workspace (3 files, 1.2 KB)
Memories: ~/.thinkingscript/thoughts/weather/memories (2 files)
Policy: 2 hosts allowed
$ thought cat weather
Figure out where I am and tell me the current
weather conditions...
$ thought run weather "NYC"
New York, NY
45°F, clear skies.
$ thought rm weather
Removed ~/.thinkingscript/bin/weather
Note: thought data remains (use --force to remove)
It becomes self-sufficient
The first time you run a thought, the agent figures out how to solve the problem. Then it writes memory.js — a JavaScript file that handles future runs without calling the agent at all.
# First run: agent works, writes memory.js (slow)
$ time weather "San Francisco"
San Francisco, CA: 62°F, Partly cloudy
real 0m45.123s
# Second run: memory.js handles it (instant)
$ time weather "San Francisco"
San Francisco, CA: 62°F, Partly cloudy
real 0m0.847s
That's 50x faster. The agent is only called when needed.
How it works
When a thought runs:
- If
memory.jsexists, run it first - If memory.js succeeds, we're done — agent never called
- If memory.js fails or calls
agent.resume(), the agent takes over
The agent can read, modify, and expand memory.js each time it's called. Over time, more cases are handled by code, fewer by the agent.
Passing control back
Sometimes memory.js encounters something it can't handle — a new input format, a failed API, an edge case. It calls agent.resume() to pass control back to the agent with context:
var location = geocode(process.args[0]);
if (!location) {
// Can't handle this input — ask the agent for help
agent.resume("Unknown location: " + process.args[0]);
}
// Otherwise, fetch weather and output it
var weather = fetchWeather(location.lat, location.lon);
process.stdout.write(formatWeather(weather));
The agent receives the message, figures out the solution (maybe adds the location to a database), and updates memory.js to handle it next time.
The sandbox
memory.js runs in a sandboxed JavaScript runtime with access to:
fs— read/write files (workspace is writable, cwd is read-only)net.fetch()— HTTP requests (requires approval)process.args— command-line argumentsprocess.stdout.write()— output to stdoutagent.resume(context)— pass control to the agent
No shell access, no arbitrary code execution. The agent writes JavaScript, and that JavaScript runs in a controlled environment.
Memories
Beyond memory.js, thoughts can save plain text notes to ~/.thinkingscript/thoughts/<name>/memories/. These are loaded into the agent's context on every run.
Weather API: Open-Meteo
- Free, no API key needed
- Endpoint: https://api.open-meteo.com/v1/forecast
- Geocoding: https://geocoding-api.open-meteo.com/v1/search
Memories are for notes and lessons learned. memory.js is for code that runs.
You're in control
Everything is just files. You can read them, edit them, or delete them.
$ cat ~/.thinkingscript/thoughts/weather/memory.js
$ rm ~/.thinkingscript/thoughts/weather/memory.js # Force fresh start
The Unix way
Unix was built on a simple idea: every program should do one thing and do it well. Then you connect them.
ThinkingScript thoughts work the same way. Each one is a small, focused tool.
clean
Normalize messy data. Fix encoding, trim whitespace, remove duplicates.
analyze
Find patterns, outliers, and trends in structured data.
summarize
Condense long text into key points.
format-report
Turn raw analysis into a readable Markdown report.
Small tools that do one thing. The power comes from how you combine them.
Pipes
The pipe (|) is Unix's greatest invention. The output of one program becomes the input of the next.
$ cat data.csv | clean | analyze | format-report > report.md
This works because ThinkingScript keeps stdout sacred. Only write_stdout touches it. Debug output, approval prompts, and status messages all go to stderr. That's what makes composition work.
$ think news.txt "AI" | think table.txt
| Headline | Source | Date |
|-----------------------------------|------------|------------|
| GPT-5 launches with native tools | TechCrunch | 2026-02-14 |
| EU passes AI Safety Framework v2 | Reuters | 2026-02-13 |
| Open-source model beats o3 on … | Ars Tech | 2026-02-12 |
Scheduling
Because thoughts are just programs, every tool that runs programs can run thoughts.
# Morning weather briefing, every day at 7am
0 7 * * * weather "San Francisco" | mail -s "Weather" me@example.com
# Stock portfolio check, weekdays at market close
0 16 * * 1-5 stocks | tee -a ~/reports/stocks.log
cron, launchd, systemd: they all work. No special scheduler, no daemon, no cloud service. The same cron that's been running jobs since 1975.
Configuration
Config is resolved in order of precedence. Higher wins.
THINKINGSCRIPT__MODEL, THINKINGSCRIPT__MAX_TOKENS, etc.
--- fences, right after the shebang
~/.thinkingscript/config.yaml
You'll need an Anthropic API key set as ANTHROPIC_API_KEY in your environment. Per-script overrides go in frontmatter, which is useful for pinning a model or setting token limits on specific thoughts.
Get started
$ curl -fsSL https://thinkingscript.com/install.sh | sh
$ thought setup
$ think https://thinkingscript.com/hi.txt