Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Reference

Configuration

oneloop reads its settings only from environment variables. There is no configuration file, and oneloop doesn’t load .env files itself. Docker or your service manager can load them for it.

  • oneloop reads the settings when it starts, so restart it after a change.
  • It refuses to start if a value is invalid, or if it finds an unknown variable that starts with ONELOOP_. This way, a typo can’t go unnoticed.
  • oneloop serve --check checks the settings, and the database if there is one, without starting the server. Run it after every change.
  • In a list separated by commas, spaces around an item and empty items, such as after a trailing comma, are ignored.
  • The other commands read only ONELOOP_DATA_DIR, and user add and user passwd also read the password settings. Still, run them as the same system account and with the same environment as the server.
VariableDefaultWhat it does
ONELOOP_PUBLIC_URLNone, requiredThe address people open, such as https://tasks.example.com. oneloop uses it for links, sign-in checks and AI assistant connections. It must use HTTPS, except for localhost, 127.0.0.1 and [::1]. Include the port if it isn’t the standard one. No path, query or credentials.
ONELOOP_LISTEN127.0.0.1:8080The IP address and port to listen on, such as 0.0.0.0:8080 or [::1]:8080. Host names don’t work here. The Docker image sets 0.0.0.0:8080.
ONELOOP_DATA_DIR./dataThe folder for the database, uploaded files and internal keys. A relative path starts from the working directory. A symbolic link followed by .. uses the linked folder’s parent, so the link must point to an existing folder. The data folder must be on a local disk; NFS and SMB aren’t supported. The Docker image sets /data.
ONELOOP_TIMEZONEUTCYour team’s timezone. See Timezone.
ONELOOP_STORAGE_LIMIT10GiBSpace for uploaded files, their previews and unfinished uploads. See Storage.
ONELOOP_DISK_MIN_FREE1GiBoneloop refuses an upload that would leave less free disk space than this. A Knowledge sync needs more; see Limits.
ONELOOP_TRUSTED_PROXIESEmpty (trust none)IP addresses or CIDR ranges of your reverse proxies, separated by commas. Only these may send the visitor’s address in X-Forwarded-For. See Trusted proxy.
ONELOOP_LOG_LEVELinfoHow much to log: error, warn, info, debug or trace.
ONELOOP_PASSWORD_MIN_LENGTH5The fewest characters in a new password, from 5 to 1,024. See Passwords.
ONELOOP_ADMIN_PASSWORD_MIN_LENGTHONELOOP_PASSWORD_MIN_LENGTHThe fewest characters in a new admin password. It can’t be lower than ONELOOP_PASSWORD_MIN_LENGTH.
ONELOOP_PASSWORD_BLOCKLISTNoneA file of passwords that nobody may choose, one per line. See Passwords.
ONELOOP_TEMPORARY_PASSWORD_LIFETIMENone (no expiry)How long a temporary password works for signing in, in hours or days, such as 36h or 7d, up to 365d.
ONELOOP_MCP_REDIRECT_SCHEMESNoneLink schemes of apps, such as cursor, that AI assistants may use for their sign-in callback, separated by commas. http, https, web+ schemes and the schemes browsers handle themselves, such as javascript and data, aren’t allowed. See AI assistant connections.
ONELOOP_MCP_ALLOWED_ORIGINSNoneOrigins of browser-based MCP clients, such as http://localhost:6274, separated by commas. Each is https:// and a host, or http:// and a loopback host, with an optional port and no path.
ONELOOP_MCP_CLIENT_METADATA_DOCUMENTSfalsetrue lets AI assistants use an HTTPS address of a client ID metadata document as their client ID. oneloop fetches the document.

Logs go to standard error. In a terminal they are colored, unless NO_COLOR is set.

Timezone

One timezone applies to the whole instance. It decides when a deadline day ends, where today is on the Roadmap, and how dates and times are shown. Use an IANA name, such as Europe/Berlin or America/New_York.

oneloop takes the rules for this name from the server’s timezone database, in /usr/share/zoneinfo or the folder that TZDIR names, when it is at least as new as the copy built into oneloop. Otherwise it uses the built-in copy. Browsers show dates and times with their own copy of the rules. The server’s clock settings and the TZ variable have no effect. oneloop serve --check prints the copy in use and its version, such as 2026e (built in).

If your region changes its clock rules, a newer tzdata package on the server brings them before a new oneloop release does; the Docker image includes the one of its Debian release. Until then, times can be an hour off, and you can set a fixed offset such as Etc/GMT+7, which means UTC−07 (the sign is reversed).

Passwords

The password settings are off until you set them. They apply whenever someone chooses a new password: when they change it, when they replace a temporary password at their first sign-in, and when you set one with oneloop user add or oneloop user passwd. The temporary passwords that admins get in the app are random and always long enough.

Signing in never checks the rules, so existing passwords keep working when you make them stricter. A person who becomes an admin keeps a shorter password until they change it.

  • ONELOOP_PASSWORD_BLOCKLIST names a text file with one password per line, such as a list of common passwords, of at most 16 MiB. Letter case doesn’t matter, and empty lines are skipped. With a list, a password that equals the username is refused too. oneloop reads the file when it starts, and refuses to start if it can’t. Give an absolute path: the server and the user commands can run in different folders, and a relative path depends on the folder.
  • With ONELOOP_TEMPORARY_PASSWORD_LIFETIME, a temporary password that is older than this no longer signs in. The person sees “This temporary password has expired”, and an admin resets it again. Temporary passwords come from Create user and Reset password in the app, and from oneloop user add and oneloop user passwd. When you turn the setting on, temporary passwords that are already older stop working at once. oneloop user passwd gives a new one, also to the last admin, whom nobody else can reset.

Storage

The storage limit covers uploaded files (attachments and avatars), their image thumbnails and unfinished uploads. The database doesn’t count, and neither do Knowledge files, which oneloop keeps in the database.

When files and unfinished uploads reach 80% of the limit, oneloop removes all image thumbnails, then temporary attachments that nobody has opened for 24 hours, until usage is back at 70%. The 24 hours start again when someone opens the attachment or marks it temporary. oneloop also removes them, at any usage, when an upload would leave less free disk space than ONELOOP_DISK_MIN_FREE. It makes a thumbnail again when someone views the image, while usage with thumbnails stays under 80%. Clean up now counts thumbnails too. oneloop never removes other files by itself.

oneloop refuses an upload when files and unfinished uploads reach the limit, or when the upload would still leave less free disk space than ONELOOP_DISK_MIN_FREE. Space that running uploads, Knowledge downloads and HTML previews being sent need counts as used. An HTML preview that would leave less free space than that shows that the server is low on disk space, and Reload preview tries again. A deleted file, or a file of a deleted task, still counts, as pending deletion, until oneloop removes it after the Undo window.

Write sizes as a whole number followed by a unit, without a space: B, KB, MB, GB or TB (powers of 1000), or KiB, MiB, GiB or TiB (powers of 1024). Units are case-sensitive, and zero isn’t allowed.

Commands

CommandWhat it does
oneloop serveRuns the web app and the MCP server in the foreground. With --check, it only checks the settings and the database, then exits.
oneloop db migrateCreates the database, or upgrades it to the current version. When it upgrades, --backup-dir <folder> is required, and oneloop saves a verified backup there first.
oneloop user add <username>Creates an account. --admin makes it an admin, and --name "<full name>" sets the name (the default is the username).
oneloop user passwd <username>Sets a new password and signs the account out everywhere.
oneloop backup create <folder>Writes a complete, verified backup to a new folder.
oneloop backup restore <folder>Restores a backup into a new or empty data directory.

oneloop --help and oneloop <command> --help show help, and oneloop --version prints the version. With Docker, run the commands in the container, for example docker compose exec oneloop oneloop backup create ….

  • Results go to standard output; errors and logs go to standard error. The exit code is 0 on success, 2 for an invalid setting, argument or value, such as an unknown ONELOOP_ variable, a data directory that isn’t a folder, or a username with spaces, and 1 for anything else, such as a username that is taken or a backup folder that already exists.
  • serve refuses to start if the database needs db migrate, or if another oneloop server uses the same data directory. serve --check never creates a database, opens a port or changes data. It also prints the versions of SQLite and of the timezone database.
  • db migrate needs the data directory to itself, even when there is nothing to upgrade: stop the server, and wait for backups and other oneloop commands to finish. serve --check works while the server runs and shows whether an upgrade is needed. There is no downgrade.
  • user add and user passwd ask for the password twice. In scripts, use --password-stdin and send the password as one line, for example oneloop user add ci-bot --password-stdin < password.txt. oneloop removes the line ending; every other character, including spaces, is part of the password.
  • New accounts must choose their own password at first sign-in. The only exception is the first admin of an empty instance.
  • user passwd works while the server runs. It also disconnects the person’s AI assistants and makes them choose a new password at their next sign-in. It doesn’t reactivate a deactivated account or change the admin role.

Limits

These limits are fixed. Only the storage limits are settings.

Files

LimitValue
Attachment size25 MiB per file
Attachments per task25
Text and Markdown previewsThe first 200 KiB
HTML previewsFiles up to 10 MiB. The server prepares two pages at once. Each person has one attachment page and one Knowledge page in line at a time, and their next one waits for it. A person can have three of each on the way; another one says at once to try again. A page that waits 5 seconds in all says that the server is busy
Image thumbnailsPNG, JPEG and WebP images within the decode limits below; at most 256 × 256 px
Avatar5 MiB, and within the decode limits below; stored as 256 × 256 px. One upload at a time per person, and 4 at once on the server
Upload in progressFails if it stalls for 60 seconds, or takes over an hour

Text and Markdown previews need the whole file to be valid UTF-8 text. The HTML limit applies each time a file opens, so attachments and Knowledge files from older versions with a lower limit preview too.

oneloop decodes one image at a time. It decodes only an image that needs at most about 192 MiB of memory, with at most 8192 px per side and 128 MiB of pixels. Some kinds of images need more memory than others, so the largest size depends on the kind:

ImageLargest size, about
Photo44 megapixels
Image with transparency33 megapixels
Progressive JPEG32 megapixels
Lossless WebP24 megapixels
16-bit PNG22 megapixels
Progressive JPEG that keeps full colour detail22 megapixels
Progressive CMYK JPEG18 megapixels
WebP with transparency18 megapixels
16-bit PNG with transparency16 megapixels
Animated WebP12 megapixels

A larger avatar is refused.

Tasks load the original file for other images, such as GIFs, and for images that oneloop can’t read or that are over these limits. A new image has its thumbnail a moment after the upload.

Knowledge

LimitValue
Folder5,000 files, links and files left out included; 5,000 subfolders; and 100 MiB of files to show. A larger folder doesn’t sync
FileFiles over 10 MiB are left out
Sync disk use300 MiB for the folder’s files and Git’s copy of them, files left out included; a larger folder doesn’t sync
Free disk spaceA download reserves 400 MiB on top of ONELOOP_DISK_MIN_FREE; a check that finds no new commit needs none
File path1,024 bytes
SyncChecks the branch every minute; after a failure, every 5 minutes
Sync timeA check stops after 30 seconds, a download after 5 minutes
Search8 words and 200 characters. One search runs at a time, and each person can have one search that runs or waits. Another search of the same person gets “try again” at once, and a search that waits 5 seconds gets it too
Searchable textMarkdown and text files up to 1 MiB; only the first 5,000 lines of plain-text files and the first 5,000 sections of Markdown files, and the first 1 KiB of each heading; in path order, as much as fits in the project’s 64 MiB search index

All query words must occur in the same file or folder path, Markdown section, or plain-text line. Matching ignores letter case. Files outside the searchable text limits can still be found by name. When some files’ text doesn’t fit in the search index, the search says that some files are searched by name only, and MCP replies include "partial": true.

Text

LimitValue
Project name60 characters
Task prefix2 to 4 uppercase letters or digits, never reused
Track name60 characters
EpicTitle 120 characters, description 2,000
MilestoneTitle 60 characters, description 500
TaskTitle 140 characters, description 4,000
Checklist50 items per task; an item is one line of 140 characters
Pool itemTitle 140 characters, description 2,000
Block reason500 characters; unblock note 500
Comment or reply2,000 characters

Some emoji count as two characters.

Accounts

LimitValue
Username3 to 32 lowercase letters, digits, ., _ or -, starting with a letter or digit
Full name80 characters
PasswordAt least 5 characters, or more with the password settings; at most 16,384 UTF-8 bytes
Sessions per account10; sign out of one to sign in somewhere new
Session lengthEnds after 7 days without use, and after 30 days at most. Automatic background requests, such as live updates and image or HTML previews, don’t extend it.
Sensitive admin actionsNeed a sign-in within the last 30 minutes
Failed sign-insWithin 15 minutes, delays start after 5 failures for one account/address pair, 20 failures from one address across accounts, or 15 failures for one account across addresses. Delays start at 30 seconds and double, up to 15 minutes for pair/address limits or 60 seconds for the account limit.

Roadmap

LimitValue
Tasks in progress drawnThree in each lane’s own work and in each epic; +N in progress counts the rest
Done tasks and dated plansAll of them, counted on their days at any scale. The page draws and loads the days it shows with half a view to spare on each side, at most 400 days in one request, and more days as you scroll
Titles of single tasksThe task of every day drawn on its own near the view loads with its days, at most 400 tasks and 400 days in one request; until it comes, a ring shows a short bar where its title goes
A read that failsThe page says Could not refresh this view and tries again by itself after 5 seconds, then 15, then every minute while the tab shows, and at once when the connection comes back; a ring whose task couldn’t load says so
ListsA number’s list, and the list of +N in progress, show 50 tasks and say how many more the Board has
OverdueSteps through the 20 longest overdue tasks; its number counts them all

Collaboration

LimitValue
@everyoneOnce a minute per person in each project
Archived Inbox itemsRemoved after 90 days; cannot be restored
Undo of a deletionWithin 5 minutes; within about a minute after that, oneloop removes the deleted files and comment text
ActivityEdits by one person to the same field within 5 minutes show as one entry. History is kept forever.

AI assistants

LimitValue
ConnectionEnds after 30 days without use, and after 90 days at most
App registrations10 per hour from one address; 300 per hour in total
Connection requests10 waiting for approval per person; another one ends the oldest. An app’s state value may be up to 4,096 bytes
File ticketsWork once and expire after 5 minutes
Items per page50 (100 for comments, activity and the Inbox)
Retry keysRemembered for 24 hours
Knowledge overview200 files, and 20,000 characters of the README
Knowledge file100,000 characters. Headings and sections come from the first 1 MiB of a Markdown file, up to 5,000 sections, and from the first 1 KiB of each heading. One file is read at a time; a read that waits 5 seconds gets “try again”

Server

LimitValue
Open connections1,024; extra connections get 503 with Retry-After: 1
Live updates16 connections per person, one for each browser tab that shows oneloop, and only from oneloop’s own pages. Another one closes the person’s oldest. That tab says its live updates are paused, and reconnects when it is shown or used again
Request headersMust arrive within 15 seconds of opening the connection, or of the previous response; within 5 minutes from a trusted proxy
Request body size256 KiB for normal requests; 1 MiB for MCP calls
Request body speedMay pause for up to 60 seconds; after the first minute, must arrive at 1 KiB per second on average
ResponseAfter the first minute of waiting, the client must read 1 KiB per second on average, or the connection closes. A client that stops reading is disconnected within 5 minutes.
Busy databaseA request waits up to 5 seconds, then gets “try again”
ShutdownOpen requests get up to 30 seconds to finish