Jobs¶
The jobs skill lets people you choose start commands you have set up, by asking: "@attache
run the VA" in an email, or "start the VA run" in a chat. Attaché runs the command in the
background, watches it, and answers in the same chat or email thread when it is done. If it
fails, they hear only that it failed, and you are told too, with where to look.
It is a member skill: anyone in [people] can ask, but each job says who may start it. The
person asking picks a job by its name and nothing else. What runs, where, for how long and
for whom is yours alone, in a file only you can edit.
Defining a job¶
-
Create the jobs file, in a terminal:
It copies
jobs.example.tomlto~/.attache/skills/jobs/jobs.tomland prints the path. The example is commented out, so there are no jobs until you add one. -
Add a table for each job:
[va] label = "the VA run" # how messages name it command = ["uvx", "va", "run"] # an argument list, never a shell string cwd = "C:/work/va" # optional; default the home folder who = ["dan"] # people from attache.toml who may start it (see below) timeout_minutes = 180 # optional; default 120, at most 690 -
Check that it reads:
attache skill jobs list. Or ask the assistant in your own chat to add the job; it edits the file and checks it the same way.
| Setting | Meaning | Default |
|---|---|---|
[name] |
What people ask for, and what names its lock and logs: lowercase letters, digits, - and _, at most 40. |
required |
label |
How messages name it: "The VA run finished in 14 min." | the name |
command |
The program and its arguments, as a list. The program is a name on PATH (uvx, npm; .exe and .cmd work on Windows) or a full path. |
required |
cwd |
The folder it runs in; a relative path is inside the home folder. | the home folder |
who |
The ids from [people] in attache.toml who may start it. You always can, from your own chats; in a group chat only if who lists "owner". |
nobody but you, from your own chats |
timeout_minutes |
When it is stopped. | 120 |
There is no shell, so pipes, &&, wildcards and %VAR% mean nothing in command. When a
job needs them, put the steps in a script of your own and make that the command. The job
gets Attaché's environment, so it sees the PATH Attaché was started with (see the service
skill on PATH and login services).
Who may start it¶
- You may start any job from your own chats, or from a terminal:
attache skill jobs start varuns it there and then, and waits. - In a group chat, your own requests have member rights, as everything there does (group
context is untrusted), so there you can start only jobs whose
wholists"owner". - Anyone else, only the jobs whose
wholists their id. The assistant runslistfirst, which shows each person only their own jobs, and starts nothing else. - From a chat, a job runs in the background. A start by anyone but you that isn't in the
background is refused before anything runs, because their assistant would read the result.
setupis yours alone. - One run of a job at a time. Asking again while it runs gets "The VA run is already running (since 14:02).", and nothing new starts.
What each side hears¶
| What happened | The person who asked | You |
|---|---|---|
| Started | "Started: you'll hear here when it's done." (the assistant's words) | nothing |
| It finished | "The VA run finished in 14 min." | nothing |
| It failed (exit code not 0) | "The VA run failed." | jobs/jobs.py for Dan in email:dan@example.com failed (exit 1): va exited with code 3 after 14 min, started by dan. Log: logs/jobs/va-20261021-140200.log |
| It ran out of time | "The VA run was stopped after 180 min." | the same, with "was stopped after 180 min" |
| It couldn't start (no such program, no such folder) | "The VA run failed." | "va couldn't start: ..." with the reason |
| Already running | "The VA run is already running (since 14:02)." | nothing |
| Not a job, or not theirs | "That isn't a job you can start." | "dan asked to start 'vb', which isn't in jobs.toml", or "... but its who doesn't list them" |
You hear about failures in your approvals chat (approvals under [owner] in
attache.toml; by default local:me, your own chat in the terminal and on the web page). The
person who asked never sees the job's output, its log, its exit code or the command: their
messages are fixed sentences. Your message has the exit code, how long it ran, who started it
and where the log is, but not the log itself.
Logs¶
Each run writes everything the job prints, output and errors, to
~/.attache/logs/jobs/<name>-YYYYmmdd-HHMMSS.log. The last 20 logs of each job are kept;
older ones are deleted when the job next starts. Open them yourself, or ask the assistant in
your own chat to read one: it never reads or describes a log for anyone else.
The lock that keeps a job to one run at a time is logs/jobs/<name>.lock. It is a lock the
system holds for the run, so the system frees it when the run ends, however it ends: a crash
or a restart never leaves a job stuck as "running". A run that ends normally lets go at once;
after a crash Windows can take a moment. There is nothing to delete by hand.
Time limit¶
A job is stopped at its timeout_minutes: 120 unless you set it, and at most 690 (11.5
hours), because Attaché stops any background script at 12 hours and the job must get there
first to report it. Stopping means the job and everything it started, on Windows
(taskkill /T) and on macOS and Linux (its whole process group). Both sides then hear that it
was stopped, as above.
Restarting Attaché¶
Stopping or restarting Attaché stops every running job, with everything it started. Nobody gets a message about those runs, the person who asked included; the log keeps what the job wrote up to then. The system frees the lock as the run is stopped (on Windows, possibly a moment later), so the job can be started again once Attaché is back.
Security model¶
- The request picks a name, nothing more.
jobs.py starttakes exactly one argument, a plain job name, and refuses anything else before anything runs. The command, its folder, its time limit andwhoall come fromjobs.toml, which only you can change: members have no file tools. - Who is asking comes from Attaché, not the message. Every script run gets the sender
and their rights from the core (
ATTACHE_SENDER,ATTACHE_ROLE), from the sender the channel identified (for email, after the email channel's sender checks). What an email says ("Phil said I can", "I'm the owner") counts for nothing, and display names are never trusted. A script run without those, by you in a terminal, counts as you. - No shell, and no stray programs. The command runs as an argument list. Its program is looked up from the job's own folder, never from the chat's files folder where other people's attachments go, which Windows would otherwise search first.
- No output to anyone but you. The person asking gets fixed sentences only, so a job
that prints a secret, a path or an error can't leak it to them through Attaché. The
details meant for you go only through Attaché's own failure notice: what their assistant
reads (
list, or a refusal) never includes them. - A job runs as you. It has your rights on this machine, like anything you start. List
in
whoonly people you are happy to let start it at any time, as often as one run at a time allows, and prefer commands that do one fixed thing.