Background Task logo

Background Task

Organization
vstorm-co
background-task

Add or change work that runs outside the request/response cycle — document ingestion, syncs, trigger fires, reports, cleanups, scheduled jobs — or debug a job that died, looped or never ran. Use when something is slow or must survive a restart, when adding a periodic job, when touching app/worker/, and before reaching for asyncio.create_task (which drops work silently in this codebase's exact failure mode).

Overview

Publishervstorm-co
Repositoryagenticos
Skill namebackground-task
Stars
137
Forks
27
Bundled files
Instructions only
LicenseApache-2.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by vstorm-co on GitHub. Read the source before you install it.

Installation

Install the Background Task AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/vstorm-co/agenticos/tree/main/.claude/skills/background-task
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/vstorm-co/agenticos.git /tmp/agenticos
mkdir -p .claude/skills
cp -r /tmp/agenticos/.claude/skills/background-task .claude/skills/background-task
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Background Task in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Background Task on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Background Task is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Background work — the job queue, and one in-process handoff

Read docs/howto/add-background-task.md. Jobs are rows in background_jobs (PostgreSQL); python -m app.worker claims and runs them. Kinds are declared in app/worker/jobs.py, handlers live in app/worker/tasks/ and are bound in app/worker/handlers.py, schedules are in app/worker/schedules.py. docs/configuration.md#background-work has the settings and the memory model.

Pick the right one

Use forSurvives a restart
A job (enqueue)Ingestion, syncs, fires, reports, anything scheduled, retryable or longYes
spawn_after_commit() from app/core/background.pyShort best-effort work on the API's loop that reads a row this unit of work wroteNo
spawn(), same moduleThe same, when it reads nothing the request wroteNo
InlineFast, transactional work the response depends onn/a
python
# AgentTriggerService.queue_fire, as it is
from app.services.background_jobs import enqueue
from app.worker.jobs import FIRE_TRIGGER, FireTrigger

await enqueue(
    self.db,
    FIRE_TRIGGER,
    FireTrigger(trigger_id=trigger_id, event_context=event_context, claimed_at=claimed_at),
    organization_id=organization_id,
)

Queue in the caller's transaction, from a service. The job row commits with the rows it names and NOTIFY fires only on commit, so the #417 race (a task that started before the commit and could not see its row) cannot happen. spawn_after_commit is still right for work that may be lost on a restart without harm; anything that must happen is a job.

Never bare asyncio.create_task. The event loop holds it only weakly, and an exception in a discarded task is never retrieved. app/core/background.py fixes both; drain(timeout=30.0) is its shutdown counterpart, and a CLI command that spawns work must call it before returning.

app/worker/background/channel.py is the older in-process fallback for channel work, dispatched with fire_and_forget(coro, *, label=...): no retry, no persistence. Do not add to it.

Add a job kind

  1. Declare a Payload and a Task in app/worker/jobs.py — pool, attempts, timeout, priority. Attempts follow one rule: 3 by default, 2 for ingestion, 1 for a scheduled sweep (its next tick is its retry) and for an API run.
  2. Write the handler in app/worker/tasks/<area>_tasks.py; it opens its own session (get_worker_db_context) and may return a Pydantic model as the job's result.
  3. Bind it in production() in app/worker/handlers.py. A sweep that takes no payload is wrapped with _each_tick.
  4. Queue it from a service with enqueue, or add a Schedule to SCHEDULES. test_every_declared_schedule_names_a_task_the_worker_knows fails a schedule with no handler.

Pick the pool by what the job spends: agent for model-bound runs, ingest for parsing and embedding (each job in a child process under a memory watchdog), system for short sweeps.

Rules

  • The attempt is spent at the claim. A job that kills its process - OOM, SIGKILL - has used one, so it cannot loop. Never move the increment out of the claim (_CLAIM in app/repositories/background_job.py). This is a hard requirement, measured against five other engines in #2219.
  • Fence every write. A job is settled with the attempts it was claimed with; a worker whose lease was taken over writes nothing and the takeover is counted as lease_lost. Handlers that charge money or send mail must be safe to run twice anyway: a lost lease means it may have.
  • Serializable payloads only — ids and primitives, never ORM objects. The handler re-reads the row and re-establishes authority (ApiKeyService.context_for_key for a key, active membership for a person): by then it may be gone.
  • Heavy imports inside the handler module, not in jobs.py, so the API that queues never imports the parser that runs.
  • Record what was spent even when the job fails. Embedding spend goes to ingestion_spend; a cost that lands only on success is a budget with a hole.
  • No ambient tenant in a worker. A job that touches an org-scoped resource carries the organization id in its payload; organization_id on enqueue is only for the panel's filter.
  • dedupe_key / dedupe_active / concurrency_key instead of checking for a running job by hand - the partial unique indexes make them race-free.

Debugging

  • Admin → Background jobs shows every job's attempts and last error, the workers alive, the paused kinds and the schedules. agenticos cmd doctor fails when no worker has beaten for two minutes, a minute schedule stopped firing, or a kind is paused.
  • A kind paused by the breaker (WORKER_BREAKER_DEATHS worker deaths in a row) stays paused until an owner resumes it; fix the cause first.
  • Tests: tests/integration/test_background_job_queue.py, tests/integration/test_worker_runtime.py (real kills), tests/test_worker_child_pool.py; misbehaving test kinds are in tests/worker_handlers.py. See docs/testing.md#the-workers-tests.

Frequently asked questions

What does the Background Task AI skill do?

Add or change work that runs outside the request/response cycle — document ingestion, syncs, trigger fires, reports, cleanups, scheduled jobs — or debug a job that died, looped or never ran. Use when something is slow or must survive a restart, when adding a periodic job, when touching app/worker/, and before reaching for asyncio.create_task (which drops work silently in this codebase's exact failure mode).

Why use Background Task on TypingMind?

Because you install it once and use it with any model. Background Task is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Background Task in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/vstorm-co/agenticos/tree/main/.claude/skills/background-task. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Background Task?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Background Task?

As many as you like. As long as a model supports skills, you can use Background Task with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Background Task AI skill free?

Yes. It is published on GitHub by vstorm-co under the Apache-2.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇