# croft > croft is one command-line tool for local data pipelines in TypeScript, on one DuckDB file: it ingests APIs and files, transforms them with SQL or TypeScript, keeps the tables fresh on a schedule, and lets an app read them. It needs only Bun, and it is built to be driven by a coding agent. These docs describe croft 0.2.0, the version on npm as @zabaca/croft. Every link is a Markdown page; https://croft.zabaca.com/llms-full.txt is all of them in one file. Inside a croft project, `croft docs ` prints the same Guides, Reference and error pages offline, for the version that project pins. Install: `bun add -g @zabaca/croft`, then `croft init my-data`. croft needs Bun 1.3.14 or newer on macOS or Linux. ## Start here - [What croft is](https://croft.zabaca.com/docs.md): croft is one command-line tool for local data pipelines in TypeScript, on one DuckDB file, built to be driven by an agent. - [Install](https://croft.zabaca.com/docs/install.md): croft needs Bun 1.3.14 or newer on macOS or Linux. One global launcher, and a pinned copy per project. - [Quickstart](https://croft.zabaca.com/docs/quickstart.md): A croft project, a SQL transform, an API ingest and a schedule, in about five minutes. Every output on this page is from a real run of croft 0.1.0. - [With Claude Code and other agents](https://croft.zabaca.com/docs/agents.md): What croft gives an agent, where an agent finds the docs, and the one permission rule that keeps every destructive step with the person. ## Concepts - [The seven concepts](https://croft.zabaca.com/docs/concepts.md): Asset, run, key, incremental, check, schedule and secret. Everything else croft either infers or brings up when it is needed. - [Runs, staleness and previews](https://croft.zabaca.com/docs/runs.md): How croft decides what to run, what a run does when one asset fails, and the three ways to try a change, from cheapest to most real. - [Safety: confirm, trash, restore](https://croft.zabaca.com/docs/safety.md): Nothing implicit destroys ingested data. What needs a confirmation, what goes to the trash, and how to bring it back. ## Guides - [Writing an ingest: API and file templates](https://croft.zabaca.com/docs/guides/ingest.md): croft docs ingest: API and file templates - [Writing an SQL asset: the header, one SELECT, and how it is rebuilt](https://croft.zabaca.com/docs/guides/sql.md): croft docs sql: the header, one SELECT, and how it is rebuilt - [Writing a TypeScript transform: per-row (API or LLM) and whole-table templates](https://croft.zabaca.com/docs/guides/transforms.md): croft docs transforms: per-row (API or LLM) and whole-table templates - [Checks: rules every write must pass, the same in TypeScript and SQL](https://croft.zabaca.com/docs/guides/checks.md): croft docs checks: rules every write must pass, the same in TypeScript and SQL - [Scheduling: ingests that run on their own, and transforms that follow them](https://croft.zabaca.com/docs/guides/scheduling.md): croft docs scheduling: ingests that run on their own, and transforms that follow them - [Secrets](https://croft.zabaca.com/docs/guides/secrets.md): croft docs secrets: Secrets - [croft serve: a read server for apps, with the scheduler built in](https://croft.zabaca.com/docs/guides/serve.md): croft docs serve: a read server for apps, with the scheduler built in - [The read copy: warehouse.read.duckdb for GUIs and notebooks](https://croft.zabaca.com/docs/guides/read-copy.md): croft docs read-copy: warehouse.read.duckdb for GUIs and notebooks - [Renaming an asset: croft rename moves the file, the table and its state together](https://croft.zabaca.com/docs/guides/rename.md): croft docs rename: croft rename moves the file, the table and its state together - [The trash: what croft keeps before anything destructive, and how to delete or restore](https://croft.zabaca.com/docs/guides/trash.md): croft docs trash: what croft keeps before anything destructive, and how to delete or restore - [Claude Code permissions](https://croft.zabaca.com/docs/guides/claude-permissions.md): croft docs claude-permissions: Claude Code permissions ## Reference - [Commands](https://croft.zabaca.com/docs/reference/cli.md): Every croft 0.2.0 command, its usage and its options, as croft help prints them. - [croft.json](https://croft.zabaca.com/docs/reference/config.md): croft docs config - [The --json envelope](https://croft.zabaca.com/docs/reference/json.md): croft docs json - [Problems and error codes](https://croft.zabaca.com/docs/reference/errors.md): croft docs errors - [Exit codes](https://croft.zabaca.com/docs/reference/exit-codes.md): croft docs exit-codes - [Internals](https://croft.zabaca.com/docs/reference/internals.md): croft docs internals ## Optional Every error code croft reports, one page each, the same as `croft docs `. - [AMBIGUOUS_DATE_FORMAT](https://croft.zabaca.com/docs/reference/errors/ambiguous-date-format.md): dates that read both day-first and month-first (warning) - [ASSET_BUSY](https://croft.zabaca.com/docs/reference/errors/asset-busy.md): another run is working on this asset - [ASSET_CODE_ERROR](https://croft.zabaca.com/docs/reference/errors/asset-code-error.md): the asset's own code threw an error - [ASSET_INVALID](https://croft.zabaca.com/docs/reference/errors/asset-invalid.md): an asset file that does not load, or whose definition croft cannot use - [ASSET_OPENS_DATABASE](https://croft.zabaca.com/docs/reference/errors/asset-opens-database.md): asset code imports a database driver or @zabaca/croft/read - [ASSET_RENAMED](https://croft.zabaca.com/docs/reference/errors/asset-renamed.md): an asset file was renamed outside croft; croft rename adopts its table - [BACKFILL_UNSUPPORTED](https://croft.zabaca.com/docs/reference/errors/backfill-unsupported.md): --from was given to an asset that cannot backfill a window - [BACKFILL_WOULD_DUPLICATE](https://croft.zabaca.com/docs/reference/errors/backfill-would-duplicate.md): --from on an append ingest would store rows twice, or skip some - [BUN_TOO_OLD](https://croft.zabaca.com/docs/reference/errors/bun-too-old.md): this Bun is older than croft needs - [BUN_UNTESTED](https://croft.zabaca.com/docs/reference/errors/bun-untested.md): this Bun is newer than any Bun this croft was tested on (warning) - [CATALOG_PREFIX](https://croft.zabaca.com/docs/reference/errors/catalog-prefix.md): a table named through a database or schema prefix - [CHECK_FAILED](https://croft.zabaca.com/docs/reference/errors/check-failed.md): rows broke a blocking check, and nothing was written - [CHECK_INVALID](https://croft.zabaca.com/docs/reference/errors/check-invalid.md): a check croft cannot run - [CLAUDE_FILES_OUTDATED](https://croft.zabaca.com/docs/reference/errors/claude-files-outdated.md): the project's Claude Code files are older than this croft (warning) - [COLUMN_NAME_COLLISION](https://croft.zabaca.com/docs/reference/errors/column-name-collision.md): two fields clean to the same column name (warning) - [COLUMN_STOPPED_ARRIVING](https://croft.zabaca.com/docs/reference/errors/column-stopped-arriving.md): a column that was almost always set is missing from a whole batch (warning) - [CONFIG_INVALID](https://croft.zabaca.com/docs/reference/errors/config-invalid.md): croft.json, or one of croft's own settings files, is not valid - [CONFIRMATION_REQUIRED](https://croft.zabaca.com/docs/reference/errors/confirmation-required.md): this action changes or removes data, and waits for a person's yes - [CONFIRMATION_STALE](https://croft.zabaca.com/docs/reference/errors/confirmation-stale.md): the token no longer matches what it would do - [CSV_ENCODING_GUESSED](https://croft.zabaca.com/docs/reference/errors/csv-encoding-guessed.md): a CSV file was not UTF-8, so croft guessed its encoding (warning) - [CSV_HEADER_AMBIGUOUS](https://croft.zabaca.com/docs/reference/errors/csv-header-ambiguous.md): croft cannot tell whether a CSV file's first line is its header - [CURSOR_TYPE_MISMATCH](https://croft.zabaca.com/docs/reference/errors/cursor-type-mismatch.md): an incremental cursor whose settings do not fit its column's type - [CYCLE](https://croft.zabaca.com/docs/reference/errors/cycle.md): assets read each other in a circle - [DB_BUSY](https://croft.zabaca.com/docs/reference/errors/db-busy.md): another croft process is writing the warehouse, and the wait ran out - [DB_HELD_BY_OTHER_PROGRAM](https://croft.zabaca.com/docs/reference/errors/db-held-by-other-program.md): a program that is not croft has the warehouse open - [DB_NEWER_FORMAT](https://croft.zabaca.com/docs/reference/errors/db-newer-format.md): a newer croft or DuckDB wrote this database - [DB_NOT_FOUND](https://croft.zabaca.com/docs/reference/errors/db-not-found.md): the database a command needs does not exist - [DB_ON_SYNCED_FOLDER](https://croft.zabaca.com/docs/reference/errors/db-on-synced-folder.md): the warehouse or .croft/ is inside a synced folder (warning) - [DB_UNREADABLE](https://croft.zabaca.com/docs/reference/errors/db-unreadable.md): the warehouse file exists but cannot be opened as a DuckDB database - [DDL_AFTER_DML](https://croft.zabaca.com/docs/reference/errors/ddl-after-dml.md): croft tried to change a table's columns after writing it in the same transaction - [DECIMAL_PRECISION_UNSUPPORTED](https://croft.zabaca.com/docs/reference/errors/decimal-precision-unsupported.md): a DECIMAL pin with more digits than a JavaScript number carries - [DUCKDB_BINDING_LOAD](https://croft.zabaca.com/docs/reference/errors/duckdb-binding-load.md): the DuckDB driver is installed but does not load here - [DUCKDB_BINDING_MISSING](https://croft.zabaca.com/docs/reference/errors/duckdb-binding-missing.md): the DuckDB driver for this machine is not installed - [DUPLICATE_OUTPUT_COLUMN](https://croft.zabaca.com/docs/reference/errors/duplicate-output-column.md): an SQL asset's SELECT returns two columns with one name - [DUPLICATE_ROWS_ACROSS_FILES](https://croft.zabaca.com/docs/reference/errors/duplicate-rows-across-files.md): identical rows came from different files, and the asset has no key (warning) - [EDITED_SINCE_LAST_RUN](https://croft.zabaca.com/docs/reference/errors/edited-since-last-run.md): the asset's code changed since its table was built (warning) - [EMPTY_EXTRACT](https://croft.zabaca.com/docs/reference/errors/empty-extract.md): an ingest with a lookback got no rows, though its window held rows last time (warning) - [ENV_FILE_IGNORED](https://croft.zabaca.com/docs/reference/errors/env-file-ignored.md): a .env.* file whose values croft does not read (warning) - [ENV_FILE_INVALID](https://croft.zabaca.com/docs/reference/errors/env-file-invalid.md): a line of .env that croft cannot parse (warning) - [FILE_NOT_FOUND](https://croft.zabaca.com/docs/reference/errors/file-not-found.md): a file ingest's path or glob matches no file - [FILE_UNREADABLE](https://croft.zabaca.com/docs/reference/errors/file-unreadable.md): a file ingest found a file it cannot read - [HEADER_UNKNOWN_KEY](https://croft.zabaca.com/docs/reference/errors/header-unknown-key.md): an SQL header line with a name croft does not know - [HTTP_ERROR](https://croft.zabaca.com/docs/reference/errors/http-error.md): a request an asset made failed - [INCREMENTAL_WITHOUT_KEY](https://croft.zabaca.com/docs/reference/errors/incremental-without-key.md): an incremental asset without a key would store re-read rows twice - [INGEST_CONFIG_CHANGED](https://croft.zabaca.com/docs/reference/errors/ingest-config-changed.md): an ingest's key, write mode or incremental field changed while it has data - [INPUT_NEEDS_KEY](https://croft.zabaca.com/docs/reference/errors/input-needs-key.md): newRows() on an input that has no key - [INPUT_NOT_BUILT](https://croft.zabaca.com/docs/reference/errors/input-not-built.md): an input has never been built, so its readers' bind check waits (info) - [INSTALL_FAILED](https://croft.zabaca.com/docs/reference/errors/install-failed.md): something croft needed to install is not in place - [INTERNAL_ERROR](https://croft.zabaca.com/docs/reference/errors/internal-error.md): a bug in croft, not in the project - [INTERRUPTED](https://croft.zabaca.com/docs/reference/errors/interrupted.md): the command was stopped before it finished - [JSON_KIND_CHANGED](https://croft.zabaca.com/docs/reference/errors/json-kind-changed.md): a JSON column now also holds another kind of value (warning) - [KEY_NULL](https://croft.zabaca.com/docs/reference/errors/key-null.md): rows without a value for the asset's key - [KEYSET_STUCK](https://croft.zabaca.com/docs/reference/errors/keyset-stuck.md): keyset pagination cannot move past a page of equal values - [LARGE_REPROCESS](https://croft.zabaca.com/docs/reference/errors/large-reprocess.md): a transform that pays per row would process many rows; a person decides - [MIXED_DATE_FORMATS](https://croft.zabaca.com/docs/reference/errors/mixed-date-formats.md): a column mixes day-first and month-first dates, so it was stored as text (warning) - [MIXED_TYPES](https://croft.zabaca.com/docs/reference/errors/mixed-types.md): a new column's values mix kinds, so it was stored as text (warning) - [NAME_CONFLICT](https://croft.zabaca.com/docs/reference/errors/name-conflict.md): two things want the same asset name - [NAME_INVALID](https://croft.zabaca.com/docs/reference/errors/name-invalid.md): a file name in assets/ that cannot be a table name - [NAME_RESERVED](https://croft.zabaca.com/docs/reference/errors/name-reserved.md): an asset name croft keeps for itself, or an SQL keyword - [NEEDS_BUN](https://croft.zabaca.com/docs/reference/errors/needs-bun.md): croft was started with Node or another runtime instead of Bun - [NULL_ONLY_COLUMN](https://croft.zabaca.com/docs/reference/errors/null-only-column.md): a column that has held only NULLs so far (warning) - [ORPHAN_TABLE](https://croft.zabaca.com/docs/reference/errors/orphan-table.md): a table whose asset file is gone (warning) - [OUT_OF_BAND_CHANGE](https://croft.zabaca.com/docs/reference/errors/out-of-band-change.md): a table was changed by something other than croft (warning) - [PIN_CHANGES_DATA](https://croft.zabaca.com/docs/reference/errors/pin-changes-data.md): a changed type pin would rewrite values already stored - [PIN_ROUNDED](https://croft.zabaca.com/docs/reference/errors/pin-rounded.md): values would be rounded to fit a column's DECIMAL pin - [PIVOT_NEEDS_VALUES](https://croft.zabaca.com/docs/reference/errors/pivot-needs-values.md): a PIVOT that does not list its values - [PROJECT_NOT_FOUND](https://croft.zabaca.com/docs/reference/errors/project-not-found.md): no croft project here - [PROJECT_NOT_WRITABLE](https://croft.zabaca.com/docs/reference/errors/project-not-writable.md): croft cannot write where it keeps the project's state - [QUERY_FAILED](https://croft.zabaca.com/docs/reference/errors/query-failed.md): DuckDB could not bind or run a query - [QUERY_NOT_SELECT](https://croft.zabaca.com/docs/reference/errors/query-not-select.md): croft query or ctx.query was given something other than one SELECT - [QUERY_PATH_DENIED](https://croft.zabaca.com/docs/reference/errors/query-path-denied.md): SQL tried to read a file or folder croft does not open for it - [QUERY_TOO_MANY_ROWS](https://croft.zabaca.com/docs/reference/errors/query-too-many-rows.md): a query for an app returned more than it may, and croft never returns part of it - [QUOTE_IDENTIFIER](https://croft.zabaca.com/docs/reference/errors/quote-identifier.md): a column named like an SQL keyword - [REQUIRES_HUMAN](https://croft.zabaca.com/docs/reference/errors/requires-human.md): this step is for a person, not an agent - [ROW_NOT_OBJECT](https://croft.zabaca.com/docs/reference/errors/row-not-object.md): rows() or map() produced something that is not a row - [RUN_CRASHED](https://croft.zabaca.com/docs/reference/errors/run-crashed.md): the process running a step died before its write committed - [SCHEDULE_HELD](https://croft.zabaca.com/docs/reference/errors/schedule-held.md): the scheduler waits until a person has run this asset's code - [SCHEDULE_INVALID](https://croft.zabaca.com/docs/reference/errors/schedule-invalid.md): an ingest's schedule croft cannot read - [SCHEDULER_STALE](https://croft.zabaca.com/docs/reference/errors/scheduler-stale.md): scheduling is on, but no scheduler tick came for 3 minutes (warning) - [SECRET_MISSING](https://croft.zabaca.com/docs/reference/errors/secret-missing.md): a secret an asset needs is not set, or not declared - [SERVE_UNAUTHORIZED](https://croft.zabaca.com/docs/reference/errors/serve-unauthorized.md): croft serve refused the request (401 or 403) - [SERVE_UNAVAILABLE](https://croft.zabaca.com/docs/reference/errors/serve-unavailable.md): croft serve did not answer, or stayed busy, for the whole timeout - [SERVE_UNSAFE_FILESYSTEM](https://croft.zabaca.com/docs/reference/errors/serve-unsafe-filesystem.md): the warehouse or .croft/ is on a filesystem where file locks do not hold - [SHRINK_GUARD](https://croft.zabaca.com/docs/reference/errors/shrink-guard.md): a replace ingest would lose more than half of its rows - [SHRINK_GUARD_DISABLED](https://croft.zabaca.com/docs/reference/errors/shrink-guard-disabled.md): an ingest turns its shrink guard off (warning) - [SINCE_IGNORED](https://croft.zabaca.com/docs/reference/errors/since-ignored.md): an incremental ingest seems to fetch everything, not what changed since (warning) - [SQL_NOT_ONE_STATEMENT](https://croft.zabaca.com/docs/reference/errors/sql-not-one-statement.md): more than one statement, or none - [SQL_NOT_SELECT](https://croft.zabaca.com/docs/reference/errors/sql-not-select.md): an SQL asset whose body is not a SELECT - [SQL_READS_FILES](https://croft.zabaca.com/docs/reference/errors/sql-reads-files.md): an SQL asset reads a file directly - [SQL_SYNTAX](https://croft.zabaca.com/docs/reference/errors/sql-syntax.md): DuckDB could not parse the SQL - [TABLE_MODIFIED_OUTSIDE_CROFT](https://croft.zabaca.com/docs/reference/errors/table-modified-outside-croft.md): a table's columns were changed by something other than croft (warning) - [TIMEOUT](https://croft.zabaca.com/docs/reference/errors/timeout.md): work made no progress, or ran longer than its limit - [TRANSFORM_MAKES_REQUESTS](https://croft.zabaca.com/docs/reference/errors/transform-makes-requests.md): a full-refresh transform makes requests (warning) - [TYPE_CONFLICT](https://croft.zabaca.com/docs/reference/errors/type-conflict.md): incoming values do not fit a column's stored type - [TYPE_PIN_VIOLATION](https://croft.zabaca.com/docs/reference/errors/type-pin-violation.md): values do not convert exactly to a column's pinned type - [TYPE_WIDENED](https://croft.zabaca.com/docs/reference/errors/type-widened.md): a column's type was widened to fit new values (warning) - [TZDATA_MISMATCH](https://croft.zabaca.com/docs/reference/errors/tzdata-mismatch.md): Bun and DuckDB disagree about the project's time zone (warning) - [UNDECLARED_INPUT](https://croft.zabaca.com/docs/reference/errors/undeclared-input.md): a TypeScript transform reads a table that is not in its inputs - [UNKNOWN_COLUMN](https://croft.zabaca.com/docs/reference/errors/unknown-column.md): SQL names a column the table does not have - [UNKNOWN_INPUT_COLUMN](https://croft.zabaca.com/docs/reference/errors/unknown-input-column.md): a TypeScript transform read a column its input does not have - [UNKNOWN_TABLE](https://croft.zabaca.com/docs/reference/errors/unknown-table.md): no table or asset of that name - [UNSAFE_INTEGER](https://croft.zabaca.com/docs/reference/errors/unsafe-integer.md): integers beyond 2^53 reached croft as JavaScript numbers (warning) - [UNSERIALIZABLE_VALUE](https://croft.zabaca.com/docs/reference/errors/unserializable-value.md): a row holds a value that cannot be stored as data - [USAGE_ERROR](https://croft.zabaca.com/docs/reference/errors/usage-error.md): the command line asks for something croft cannot do - [VOLATILE_SQL](https://croft.zabaca.com/docs/reference/errors/volatile-sql.md): an SQL asset uses a value that changes on every run (warning)