Which invoices are still unpaid? Total them and save me the list. #documents/invoices.json
your Mac · your models · your files
She does the work. And it’s all yours.
A personal assistant that lives on your Mac. What she knows and what she makes are files you keep.
One request.
you ask, in plain words
Becomes a result.
she writes a program, runs it, saves the file
Becomes a tool.
an App: one file she built, open in the conversation
Becomes a habit.
a skill: her instructions, in a file you can edit
And it’s all yours.
ordinary files in your Alice folder · quit her and they stay
Which invoices are still unpaid? Total them and save me the list. documents/invoices.json
Inspect this run
import { files } from "alice";
export default async function main() {
const { content } = await files.read({
path: "documents/invoices.json"
});
const invoices = JSON.parse(content);
const valid = Array.isArray(invoices) &&
invoices.every((invoice) =>
invoice.currency === "USD" &&
["paid", "unpaid"].includes(invoice.status) &&
Number.isSafeInteger(invoice.amountCents) &&
invoice.amountCents >= 0 &&
/^[A-Z]+-[0-9]+$/.test(invoice.id) &&
/^[A-Za-z ]+$/.test(invoice.customer)
);
if (!valid) throw new Error("Invalid invoice register");
const unpaid = invoices.filter((invoice) =>
invoice.status === "unpaid"
);
const totalCents = unpaid.reduce(
(sum, invoice) => sum + invoice.amountCents, 0
);
if (!Number.isSafeInteger(totalCents)) {
throw new Error("Total exceeds safe integer range");
}
const usd = (cents) => "USD " + (cents / 100).toFixed(2);
const rows = unpaid.map((invoice) =>
"- " + invoice.id + " · " + invoice.customer +
" · " + usd(invoice.amountCents)
);
const report = [
"# Unpaid invoices", "", ...rows, "",
"Total: " + usd(totalCents), ""
].join("\n");
const path = "documents/unpaid.md";
await files.create({ path, content: report });
return { path, count: unpaid.length, totalCents };
}[
{
"id": "INV-101",
"customer": "Cedar",
"status": "unpaid",
"amountCents": 125000,
"currency": "USD"
},
{
"id": "INV-102",
"customer": "Linden",
"status": "paid",
"amountCents": 48000,
"currency": "USD"
},
{
"id": "INV-103",
"customer": "Maple",
"status": "unpaid",
"amountCents": 62550,
"currency": "USD"
}
]{
"purpose": "Read the invoice register and create an unpaid invoice summary",
"uses": [
{
"name": "files.read",
"scope": {
"path": "documents/invoices.json"
}
},
{
"name": "files.create",
"scope": {
"path": "documents/unpaid.md"
}
}
]
}# Unpaid invoices
- INV-101 · Cedar · USD 1250.00
- INV-103 · Maple · USD 625.50
Total: USD 1875.50
This example uses contained JavaScript to read the invoices and save the result. In Alice, your permissions determine which files and tools a run can use. This offline check is not proof of execution inside Alice.
it works · press Unpaid onlyit answers · press All
------# Invoice reminderWrite to the contact about one unpaid invoice.## Tone## Always- Name the invoice and the amount.- Save a draft. **Never send.**
agents/alice.md ------You are Alice, a local personal assistant.memories/dana.md Dana is the contact at Cedar.She prefers first names and short mail.documents/unpaid.md # Unpaid invoices- INV-101 · Cedar · USD 1250.00- INV-103 · Maple · USD 625.50Total: USD 1875.50documents/apps/invoices.html <!------><div role="group" aria-label="Show"> <button type="button" data-action="show" data-arg-view="all">All</button> <button type="button" data-action="show" data-arg-view="unpaid">Unpaid only</button></div><section id="statement"></section><script>const ns = alice.app.namespace, state = { register: [], view: 'all' };const esc = (s) => String(s).replace(/[&<>"]/g, (c) => '&#' + c.charCodeAt(0) + ';');const usd = (cents) => 'USD ' + (cents / 100).toFixed(2);function draw() { const owed = state.register.filter((one) => !one.paid), shown = state.view === 'unpaid' ? owed : state.register; const rows = shown.map((one) => '<tr><td>' + esc(one.customer) + '</td><td>' + esc(one.id) + '</td><td>' + usd(one.cents) + '</td></tr>'); alice.html('#statement', '<h2>' + usd(owed.reduce((sum, one) => sum + one.cents, 0)) + ' outstanding</h2><table>' + rows.join('') + '</table>');}const read = (key) => alice.call('values.get', { namespace: ns, key }).then((r) => { state[key] = r.value; draw(); });const redraw = ({ value }) => (value ? ((state.register = value), draw()) : read('register'));alice.action('show', async ({ view }) => { state.view = (await alice.update('view', () => view)).value; draw(); });alice.on('values', 'register', redraw);alice.expose({ state: () => state });read('register'); read('view');</script>skills/invoice-reminder/SKILL.md ------# Invoice reminderWrite to the contact about one unpaid invoice.## Tone- Be **warm**. Use first names.- Give a line of context before the ask.- **Three sentences** at most.- No small talk. Get to the ask.## Always- Name the invoice and the amount.- Save a draft. **Never send.**threads/…/journal.ndjson {"v":1,"seq":1,"id":"…","at":"…","type":"message/user","data":{…}}{"v":1,"seq":2,"id":"…","at":"…","type":"model/request","data":{…}}
Every scene on this page is scripted, not a live session; it makes no model, account, or service calls.
SkipAnd it compounds.
A feeds a . A runs it. An holds it all.
four files and one schedulepress a word
scripts/unpaid_report.mjsimport { unpaid, total } from "../packages/invoices.mjs";
skills/invoice-reminder/SKILL.mdscripts: [unpaid_report] · packages: [invoices]
Unpaid invoices · the task she is givenRun the unpaid report, then draft the reminders.
documents/apps/invoices.htmlalice.on('values', 'register', redraw);
/*------*/export function unpaid(all) { return all.filter(open);}export function total(all) { return unpaid(all).reduce(add, 0);}const open = (one) => one.status === "unpaid";const add = (sum, one) => sum + one.amountCents;
------# Invoice reminderWrite to the contact about one unpaid invoice.## Tone- Be **warm**. Use first names.- Give a line of context before the ask.## Always- Name the invoice and the amount.- Save a draft. **Never send.**
Unpaid invoices
Run the unpaid report, then draft the reminders.
Latest run
Unpaid invoices
Scheduled conversation finished.
saved at 8:00 by the scheduled run
A schedule runs her, on your Mac, while it’s awake and Alice is running. A scheduled run asks like any other until you allow it for scheduled runs.
She can change herself.
her window is readypress Send, or ask something else
values.setapp.preferences · appearance.accent: green
values.setapp.preferences · appearance.accent: violet
files.replaceskills/invoice-reminder/SKILL.md · one line added
runs.schedule.saveUnpaid invoices · Weekdays · saved paused
turned on by youUnpaid invoices · Next 13 Nov 8:00 · Weekdays
Hersettings, agents, skills, packages, schedules and apps are files and values she can edit, under your permission rules.
Signing in, entering keys, picking folders and the Cloud switch stay in your hands. Changing herself gives her no new permissions.
Use a green accent.
skills/invoice-reminder/SKILL.md
13 unchanged lines## Always- Name the invoice and the amount.- Keep it to **two sentences**.- Save a draft. **Never send.**Unpaid invoices
Run the unpaid report, then draft the reminders.
Unpaid invoices
Run the unpaid report, then draft the reminders.
Bring what you use.
Your services,her tools.
A remote MCP server by its address, or a web service from its API documentation. By default each call asks first.
“Connect my MCP server at https://mcp.ledger.example/mcp”
Integrations
- OpenAI
- Anthropic
- LedgerMCP
- MailerWeb service
- LM StudioModel server
The web,with sources.
Search runs through your model provider's own search and keeps the links.
Say it.Hear it back.
Dictate a message. Have a reply read aloud. Both use an OpenAI or Gemini key.
0:07
Remind Cedar about INV-101, and keep it warm.
dictates with OpenAI · reads aloud with Gemini
Every conversation,found.
History finds a conversation by its title, its agent, or the words in a message.
- Unpaid invoices
- Cedar reminder
- Has Maple paid INV-103?
- Tighten the offer
On your terms.
Permission,not forgiveness.
By default she asks before she creates, changes or deletes a file.
Nothing was written.
She will ask again.
INV-101 for USD 1250.00 is still open, Dana.Could you confirm the payment date?---id: remember-4f2a…decision: allowagent_ids:- aliceorigins:- userprimitive: filesverb: createresource: type: workspace_path path: documents/replies/cedar-reminder.md descendants: false---Remembered human allow from grant request evt_… on thread ….---id: remember-4f2a…decision: allowagent_ids:- aliceorigins:- userprimitive: filesverb: createresource: type: workspace_path path: documents/replies/cedar-reminder.md descendants: false---Remembered human allow from grant request evt_… on thread ….The modelis a setting.
An API key, your ChatGPT plan, Included AI, or a model server on your Mac.
Answers come through OpenAI, paid with your OpenAI key.
agents/alice.md · model: connection: openai
Answers come through Anthropic, paid with your Anthropic key.
agents/alice.md · model: connection: anthropic
Answers come through Gemini, paid with your Gemini key.
agents/alice.md · model: connection: gemini
Answers come through xAI, paid with your xAI key.
agents/alice.md · model: connection: xai
Answers come through OpenRouter, paid with your OpenRouter key.
agents/alice.md · model: connection: openrouter
skills · memories · conversations · unchanged
Copy. Press.Paste.
Any skill on a shortcut, in any app.
hey dana did u maybe get a chance to look at inv-101 yet??
Dana, have you looked at INV-101 yet?
Hej Dana, udało Ci się może zajrzeć już do INV-101?
or press ⌃⌥T now
Reply copied.
Close the window.She stays.
Work continues.
Questions wait for you.
window closed · Alice is in the menu barResearcher has a question
Private by design.Cloud by choice.
Stored on your Mac. Nothing goes to Alice’s servers unless you turn on Cloud.
Account
Cloud
Cloud
Turn on Cloud?
Your conversations, files, settings and API keys go to Cloud and stay in sync with this Mac; linked folders and connected services stay here.
your MacAlice’s servers
When you use them, online models and connected tools receive the inputs they need. Cloud is in private testing; no date, plan or price is set. Encrypted at rest, not end-to-end: the server holds the key so it can run your work while your Mac is off.
From people who use Alice
Since I started using Alice, it has become an essential tool in my work. It is reliable, and the possibility of integrating it with automations brings a whole new dimension to optimizing processes in the company and increasing personal productivity!
What wouldyou ask?
Start with one request. See what it becomes.