跳到正文
DEV Community· Gavin Rose·· 4 小時前AI 評分46

Bastion,本地助手

Bastion, the Local Helper

AI 導讀

Bastion 是一個本地 AI 智能體,會按用戶提示建立並排程執行日常任務;Gemma 4 12B 在 Ollama 上編寫及修復 Python 腳本,Gemma 3 4B 則負責每日摘要。腳本須先在沙盒中測試並經用戶批准,之後按排程以一般程式碼執行,除非需要生成摘要,否則不會再調用模型。

正文

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady

What I Built

Bastion is a local agent that does chores based on the prompt you give it.

You describe a chore in plain English:

Every Friday, go through my Downloads folder and move all .jar files into a folder called minecraft.

Every morning at 9:30, check the news on artificial intelligence and summarize anything new.

A local model writes a small Python script for it, tests it as a dry run in a sandbox, and shows you exactly what it will be allowed to do. It slowly fixes itself if any issues are present, then, you only have to approve it once. From then on the chore runs on schedule as plain code. No model is involved, unless you asked for the results to be summarized. Every run after that is fast, cheap and predictable, and the only thing you do is read the result.

It's built for people who don't write code. You never have to edit a script. You read a plain list of permissions ("can reach news.google.com", "can move files in ~/Downloads and to the Trash"), look at a sample result, and click approve.

How I Built It

The open pieces

  • Gemma 4 12B (Google's QAT build) writes and repairs scripts, run locally with Ollama.
  • Gemma 3 4B writes the daily summaries.
  • Bastion talks to Ollama over stdio: the prompt goes in on stdin, a JSON schema goes in with ollama run --format, and structured JSON comes back on stdout. The grammar keeps the model's output valid, and length limits in the schema stop runaway loops.
  • Elixir / Phoenix LiveView runs the background service and the dashboard.

How a chore gets made

"every Friday, move .jar files from Downloads into Downloads/minecraft"
        │
        ▼
 look around (read-only, sandboxed): list folders, fetch the feed or API, check tools exist
        │
        ▼
 Gemma 4 12B plans (JSON): permissions, schedule, which library example to start from
        │
        ▼
 Gemma 4 12B writes the script (plain Python on top of a small tested helper kit)
        │
        ▼
 dry-run test in the sandbox ──fails──► look again, read the error, revise (up to 2 times)
        │ passes
        ▼
 you approve, in plain English
        │
        ▼
 one supervised process per chore runs it on schedule

OTP does the boring, important parts. Every approved chore gets its own GenServer under a DynamicSupervisor. Runs happen in unlinked tasks, so a crashing script never takes its scheduler down. Failures retry with backoff (seconds for a broken run, 10 to 30 minutes when a site is rate limiting). A janitor process marks interrupted runs as stopped, and every run can be stopped from the dashboard, which kills the actual sandboxed process.

The sandbox is enforced by the kernel, not by asking nicely. Every script runs under macOS sandbox-exec:

  • Network: blocked, except for a per-run proxy that only forwards to the domains you approved. It logs anything it blocks.
  • Writes: blocked, except for the chore's own memory folder and the folders you approved. Test runs are dry runs where even those are read-only.
  • Programs: nothing runs except Python and the commands you approved. No shell.
  • Secrets: SSH keys, cloud credentials, the Keychain, browser data, Mail, shell history and .env files can't be read at all.
  • Deleting: scripts never delete. Anything removed goes to the Trash, and any run that moved files has an Undo button.

It respects scraping and other bot rules. Scraped pages respect robots.txt, feeds and public APIs are preferred, rate limits are waited out instead of hammered, and sites that send Content-Signal: ai-input=no (like Lobsters) never have their content passed to a model. You still get the plain list, just not an AI summary of it.

What I learned about small local models (this was the most interesting part)

I tested three 12B models on the same chores, drafted from scratch with no example to copy:

Model What happened
Gemma 4 12B, community "abliterated" build Garbled text: retmah=10, efetch.fcji, invented hostnames
Gemma 3 12B (official) Clean text, but sent the same failing request five times in a row
Gemma 4 12B (official) Read the API's error messages and corrected its own requests

None of them can reliably learn an unfamiliar web API on its own, so Bastion leans on things code can check:

  • probes verify every URL before it's used;
  • Bastion, not the model, decides whether a request actually worked;
  • when an API rejects a parameter, Bastion reads that API's docs page and hands the model the real names;
  • the model adapts small, tested library examples instead of starting from nothing.

Where the models do shine is on your own machine. Cleanup chores worded the way a non-programmer would ask (duplicate files, screenshot filing, old installers, big untouched files) passed on the first try, 4 out of 4.

Why Does Open Innovation Matter?

For this project it's not a nice-to-have, it's the whole design:

  • Your files stay yours. Bastion's models see folder listings, git repos, the names of things in your Downloads. With open weights running locally, none of that leaves the laptop. The only network traffic is the requests a chore makes to the sites you approved.
  • Doing nothing costs nothing. A chore that runs every day for a year would be hundreds of paid API calls. Here the model runs once, and daily runs are just Python.
  • I could swap and tune models freely. The three-way comparison above took an afternoon: pull a model and change one line of config. When the community build kept garbling text, I switched to Google's official one. When a model's default 8K context was too small for my prompts, a three-line Ollama Modelfile gave it 16K. A closed API wouldn't let me do any of that.
  • Structured output at the grammar level. Ollama enforces the JSON schema while the model generates, and it enforces length limits too. That's what stopped a small model's repetition loops from wrecking a run.
  • Local chores work offline. Tidying folders, finding duplicates, checking git repos: none of it needs the internet at all.

The Lazy Payoff

I've been running it on my own machine this week:

  • Daily news chores (AI news, and research) turn a feed of 30 to 100 headlines into a handful of relevant bullets, with Markdown and PDF export.
  • A weekly Downloads tidy for Minecraft .jar files, set up in one sentence.
  • Test runs on my real folders showed what the cleanup chores would handle: 423 screenshots and screen recordings to file into monthly folders, 134 old installers and archives to send to the Trash (one of them a 91.8 GB zip from 97 days ago), and duplicate sets across about 35,000 files. Each of those is a chore I'd been putting off for months, and now it's one sentence and one click.

來源:DEV Community · dev.to