# FlightSQL Source: https://docs.kamu.dev/api/flight-sql [Arrow Flight SQL](https://arrow.apache.org/docs/format/FlightSql.html) is a protocol for interacting with SQL databases using the Arrow in-memory format. It is column-oriented, compact, and extremely performant compared to legacy protocols such as [JDBC](https://en.wikipedia.org/wiki/Java_Database_Connectivity) and [ODBC](https://en.wikipedia.org/wiki/Open_Database_Connectivity). FlightSQL endpoint is typically exposed as: ``` datafusion+flightsql://kamu:kamu@:50050?insecure=True ``` Please refer to [Integrations](/integrations) page for some examples of FlightSQL protocol use. # GraphQL Source: https://docs.kamu.dev/api/graphql [![GraphQL API](https://img.shields.io/static/v1?logo=graphql\&logoColor=F133A8\&label=\&message=GraphQL%20API\&color=gray\&style=for-the-badge)](https://api.demo.kamu.dev/graphql) [GraphQL](https://graphql.org/) is our primary API for interacting with the node when building rich applications. [Kamu Web Platform](/platform) uses it extensively. Here you can access [interactive GraphQL playground](https://api.demo.kamu.dev/graphql) of our demo node. The playground is also available when you run your local node or when you use `kamu system api-server` CLI command under the HTTP port. Here you can find the latest version of static [GraphQL API schema](https://github.com/kamu-data/kamu-cli/blob/master/resources/schema.gql). # JDBC Source: https://docs.kamu.dev/api/jdbc **🚧 This page is under construction 🚧** Kamu Node supports JDBC protocol through FlightSQL adapter. To use it you will need a special client-side driver JAR. Please see instruction for connecting [DBeaver](/integrations/dbeaver) and [Tableau](/integrations/tableau) to Kamu for guidance on where to download the drive and how to configure the connection. # Kafka Source: https://docs.kamu.dev/api/kafka # MQTT Source: https://docs.kamu.dev/api/mqtt **🚧 This page is under construction 🚧** Kamu Node supports ingesting data using the [MQTT](https://mqtt.org/) protocol. See and this [example](https://github.com/kamu-data/kamu-cli/tree/master/examples/mqtt). In current implementation Kamu Node acts as an MQTT **client** that subscribes to a given set of topics , meaning that an external broker is required to ingest MQTT data, and this broker needs to be accessible to wherever environment Kamu Node is running. In future versions we are planning to add support for a simple publish-only **broker** in Kamu Node itself, allowing you to connect MQTT devices to it directly. If your use case requires this - let us know! ## Data Delivery Guarantees Kamu Node may not have perfect connectivity with MQTT broker, so prolonged periods of disconnects should be accounted for. Additionally, MQTT sources can be used even with [kamu-cli](/cli) tool, and since the tool doesn't use any background processes it will connect to MQTT broker only when you run: ```sh theme={null} kamu pull my-mqtt-device ``` What data `kamu` can get when it is connected to the broker depends on: * [Retained](https://www.hivemq.com/blog/mqtt-essentials-part-8-retained-messages/) message mode * [QoS level](https://www.hivemq.com/blog/mqtt-essentials-part-6-mqtt-quality-of-service-levels/) of the publisher (e.g. device) and the subscriber (`kamu`) * Implementation of your MQTT broker - since delivery semantics is left under-specified in the core MQTT spec. For example: * `retained: true, qos: 0 (at most once)` - will ensure that broker remembers the last message from a device and always transmits it to `kamu` upon reconnect. This mode is sufficient for a lot of cases e.g. where device periodically reports temperature data and `kamu` periodically ingests the readings on its own schedule. * `retained: false, qos: 1 (at least once)` - will *likely* make broker to buffer all messages from the device and deliver them to `kamu` upon reconnect. This mode is good for devices like door sensors, where the whole series of events matters. The exact behavior is very broker-specific, so make sure to read you broker's documentation. You can use [merge strategies](/cli/ingest/merge-strategies) to avoid duplication of retained data in your dataset. # OData Source: https://docs.kamu.dev/api/odata Kamu Node has an experimental support for [OData](https://www.odata.org/) protocol. The endpoints structured with one OData service root per every account: ``` /odata/{account}/ /odata/{account}/$metadata ``` Every dataset in the account has a corresponding collection endpoint: ``` /odata/{account}/{dataset} ``` Examples: ``` https://node.demo.kamu.dev/odata/kamu/ https://node.demo.kamu.dev/odata/kamu/$metadata https://node.demo.kamu.dev/odata/kamu/co.alphavantage.tickers.daily.spy https://node.demo.kamu.dev/odata/kamu/co.alphavantage.tickers.daily.spy?$select=offset,close&$orderby=offset+asc&$top=10 ``` You can find more endpoint information in [OpenAPI documentation](/api/rest/). See documentation of our [datafusion-odata](https://github.com/kamu-data/datafusion-odata/) library for the list of limitations. # ODF Source: https://docs.kamu.dev/api/odf **🚧 This page is under construction 🚧** Kamu Node implements both Simple and Smart Transfer Protocols according to the [ODF Specification](/odf/spec/overview). [Simple Transfer Protocol](/odf/spec/exchange/transfer-protocols#simple-transfer-protocol) (HTTP / REST) can be used for data access via HTTP in constrained environments. [Smart Transfer Protocol](/odf/spec/exchange/transfer-protocols#smart-transfer-protocol) (HTTP + Websocket) provides the most efficient way to download and upload datasets. Thanks to native support of pre-signed URLs they avoid proxying large chunks of data through the API server and instead can direct uploads and downloads directly to your storage system. Built-in metadata compression also ensures best performance and optimal use of bandwidth for datasets with very large histories. You can see individual endpoints of ODF protocol in our [REST API documentation](/api/rest). # Blockchain Oracle Source: https://docs.kamu.dev/api/oracle Oracle API allows you to perform SQL queries over massive volumes of data in the ODF network directly from smart contracts. It's the first of a kind **optimistic oracle** that enables reproducibility and verifiability of requests without an expensive consensus protocol (more on this [below](#verifiability)). ## Example Example of the Solidity contract using ODF oracle: ```solidity theme={null} // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.25; import { OdfRequest, OdfResponse, IOdfClient, CborReader } from "@opendatafabric/contracts/Odf.sol"; // This sample contract makes an ODF oracle query to calculate // a Canadian province with the most recorded COVID-19 cases contract TestConsumer { using OdfRequest for OdfRequest.Req; using OdfResponse for OdfResponse.Res; using CborReader for CborReader.CBOR; IOdfClient private oracle; string public province; int public totalCases; // Initialize contract with the oracle address constructor(address oracleAddr) { oracle = IOdfClient(oracleAddr); } function initiateQuery() public { OdfRequest.Req memory req = OdfRequest.init(); // Specify ID of the dataset(s) we will be querying. // Repeat this call for multiple inputs. req.dataset( "covid19.canada.case-details", "did:odf:fed01c8788dc7825dc95dfaa6c67f989b758d3ebcb1efcb9f47ea914470bd1f7f2bbb" ); // Specify an arbitrary complex SQL query. // Queries can include even JOINs req.sql( "with by_provice as ( " " select " " province, " " count(*) as count " " from 'covid19.canada.case-details' " " group by 1 " "), " "ranked as ( " " select " " row_number() over (order by count desc) as rank, " " province, " " count " " from by_provice " ") " "select " " province, " " count " "from ranked where rank = 1" ); // Send request to the oracle and specify a callback oracle.sendRequest(req, this.onResult); } // This function will be called by the oracle when // request is fulfilled by some data provider function onResult(OdfResponse.Res memory result) external { // Important: Make sure only the ODF oracle can supply you data require(msg.sender == address(oracle), "Can only be called by oracle"); // We expect only one row: [province, totalCases] require(result.numRecords() == 1, "Expected one record"); CborReader.CBOR[] memory record = result.record(0); province = record[0].readString(); totalCases = record[1].readInt(); } } ``` ## Getting Started Start by installing [`@opendatafabric/contracts`](https://www.npmjs.com/package/@opendatafabric/contracts) package that contains oracle interface and request/response types. ```sh theme={null} npm i @opendatafabric/contracts ``` See the example above for the recommended way of forming requests and decoding results. More examples, documentation, and tests can be found in the [contracts repository](https://github.com/kamu-data/kamu-contracts). ## Supported Networks | Network | Contract Address | Oracle Fee | | :- | :- | - | | [Ethereum Sepolia Testnet](https://chainlist.org/chain/11155111) | [`0xf1960569d1b4a23c34109d9341af6496ed90c0c3`](https://sepolia.etherscan.io/address/0xf1960569d1b4A23c34109D9341Af6496Ed90C0c3#events) | 0 | | [BNB Smart Chain Testnet](https://chainlist.org/chain/97) | [`0x83857865971e941933dd36ebbf9475a867f67ca6`](https://testnet.bscscan.com/address/0x83857865971e941933dd36ebbf9475a867f67ca6#events) | 0 | | Ethereum Mainnet | *coming soon* | 0 | | Optimism | *coming soon* | 0 | ODF oracle can be deployed on any EVM-compatible chain - you can request network support by filing an issue on the [contracts repository](https://github.com/kamu-data/kamu-contracts). Oracle contract and all providers currently operate with **zero fees**. ## Verifiability Every response submitted to the oracle by data providers includes special data that allows the query to be reproduced later against the same exact version of input data. In REST API semantics an oracle request that looks like this: ```json theme={null} { "query": "select offset, city, population from populations order by offset desc", "queryDialect": "SqlDataFusion", "datasets": [{ "id": "did:odf:fed0119d20360650afd3d412c6b11529778b784c697559c0107d37ee5da61465726c4", "alias": "populations" }], "dataFormat": "JsonAoA", "include": ["input"], } ``` Will be given a result such as: ```json theme={null} { "input": { "query": "select offset, city, population from populations order by offset desc", "queryDialect": "SqlDataFusion", "dataFormat": "JsonAoA", "include": ["Input"], "datasets": [{ "id": "did:odf:fed0119d20360650afd3d412c6b11529778b784c697559c0107d37ee5da61465726c4", "alias": "populations", "blockHash": "f1620708557a44c88d23c83f2b915abc10a41cc38d2a278e851e5dc6bb02b7e1f9a1a" }] }, "output": { "data": [ [1, "B", 200], [0, "A", 100] ], "dataFormat": "JsonAoa" } } ``` The `input.datasets` block of the response contains state information that associates every input dataset with the hash of the last block that was considered during the query. Whenever a provider supplies a response - this state information is recorded in the events emitted by the oracle contract on the blockchain. This data acts as a **commitment** using which a data consumer can **dispute** results of a query. If another party repeats the same computations using the state data and arrives at different result - this means that the original provider has acted maliciously. See [commitments documentation](/node/commitments) for details. The reproducibility and verifiability of queries therefore make ODF the first of a kind **optimistic oracle** where: * Queries can be fulfilled fast and cheap just by one provider * Without going through a complex consensus mechanism * While validity of data can still be ensured through the dispute resolution and sampling mechanisms along with staking and slashing. ## Commitment Properties Using the criteria discussed in the [commitments documentation](/node/commitments) the oracle commitment can be described as follows: * **Hiding** - NO * The entire request and response data is publicly available, but this as an inherent limitation of non-ZK blockchains * **Binding** - YES * All inputs and outputs are immutably stored on-chain * **Succinct** - YES\* * All response data ends up stored which we cannot avoid, but the commitment itself does not add much overhead * **Deterministic** - YES * **Reproducible** - YES * Original query with all of its parameters is stored on-chain and can be repeated against the state information in response * **Non-repudiable** - YES * Automatically achieved as the provider signs the response transaction with its private key * **Composable** - YES * Through recursive nature of the commitment ## Troubleshooting To better understand what oracle providers return find the incoming oracle transaction in the block explorer e.g. [0x0f3a..4ff6](https://sepolia.etherscan.io/tx/0x0f3af200610ee2a11b13afda14eea808b04cbe012197a352ec95b558bbce4ff6). Find the `ProvideResults` log: Copy the data field and paste it in [https://cbor.me/](https://cbor.me/) to get something like this: The first three fields are: `version`, `success`, `data`. Refer to [`OdfResponse`](https://github.com/kamu-data/kamu-contracts/blob/e25e896ede177fdac7d34e9a4a3330094d23cc6f/src/OdfResponse.sol#L9) to understand the layout of the other fields. Once you have one oracle response - you can use it as input in your unit tests to fully debug the decoding and processing logic without constantly re-deploying the contract and spending a lot of gas. Here's an example of one such tests in `foundry`: ```solidity theme={null} function testResponseDecoding() public pure { bytes memory responseBytes = hex"8501F58A826..92AFE32"; OdfResponse.Res memory res = OdfResponse.fromBytes(0, responseBytes); assertEq(res.numRecords(), 10); CborReader.CBOR[] memory record = res.record(0); string memory voiceId = record[0].readString(); int256 playtimeTotal = record[1].readInt(); assertEq(voiceId, "lana-del-rey"); assertEq(playtimeTotal, 6449); } ``` ## Registering Your Own Provider **🚧 Under construction 🚧** - contact us if you'd like to use ODF oracle contract along with your private ODF node. # Overview Source: https://docs.kamu.dev/api/overview Kamu Node supports multiple network protocols for managing metadata, bulk uploads/downloads of datasets, and querying data. Not sure where to start? Here are some suggestions: * [REST](/api/rest) is best for interacting with the node from scripts, libraries, and system-to-system integration * [GraphQL](/api/graphql) is best for interacting with the node when building rich applications * [FlightSQL](/api/flight-sql) is the most modern way to connect SQL-based systems together including various BI and analytics tools * [MQTT](/api/mqtt) is used to ingest real-time data from IoT devices * [OData](/api/odata) can be used to integrate with some legacy systems * [Blockchain Oracle](/api/oracle) can be used to query data directly from nodes into smart contracts # PostgreSQL Source: https://docs.kamu.dev/api/postgres # REST Source: https://docs.kamu.dev/api/rest [![REST API](https://img.shields.io/static/v1?logo=openapiinitiative\&logoColor=6BFF39\&label=\&message=REST%20API\&color=gray\&style=for-the-badge)](https://api.demo.kamu.dev/openapi) REST is our primary API for interacting with the node from scripts, libraries, and system-to-system integration. Here you can find the latest [OpenAPI documentation](https://api.demo.kamu.dev/openapi) along with usage examples. Interactive Swagger UI is also available on HTTP port of all running nodes. If you are considering to build applications on top of Kamu Node - also consider using [GraphQL API](/api/graphql). For accessing individual components of the datasets (blocks, references, data slices) you can use [ODF protocol](/api/odf). ## Reading Data To get dataset information like description, schema, etc. use `/metadata` endpoint: ``` https://node.demo.kamu.dev/kamu/com.cryptocompare.ohlcv.eth-usd/metadata?include=attachments,info,license,refs,schema,seed,vocab ``` To get sample data from any dataset use `/tail` endpoint: ``` https://node.demo.kamu.dev/kamu/com.cryptocompare.ohlcv.eth-usd/tail?limit=10 ``` To execute arbitrary SQL that can access multiple datasets at once use `/query` endpoint: ``` https://node.demo.kamu.dev/query?query=select+1&skip=0&limit=10&include=input,schema ``` The `/query` endpoint also supports `POST` requests for finer control: Example request body: ```json theme={null} { "query": "select event_time, from_symbol, to_symbol, close from \"kamu/com.cryptocompare.ohlcv.eth-usd\"", "limit": 3, "queryDialect": "SqlDataFusion", "dataFormat": "JsonAoa", "schemaFormat": "ArrowJson" } ``` Example response: ```json theme={null} { "output": { "data": [ ["2024-09-02T21:50:00Z", "eth", "usd", 2537.07], ["2024-09-02T21:51:00Z", "eth", "usd", 2541.37], ["2024-09-02T21:52:00Z", "eth", "usd", 2542.66] ], "dataFormat": "JsonAoa", "schema": {"fields": ["..."]}, "schemaFormat": "ArrowJson" } } ``` ## Cryptographic Proofs [Cryptographic proofs](/node/commitments) can be also requested to hold the node **forever accountable** for the provided result. Example request body: ```json theme={null} { "query": "select event_time, from_symbol, to_symbol, close from \"kamu/com.cryptocompare.ohlcv.eth-usd\"", "limit": 3, "queryDialect": "SqlDataFusion", "dataFormat": "JsonAoA", "schemaFormat": "ArrowJson", "include": ["proof"] } ``` Example response: ```json theme={null} { "input": { "query": "select event_time, from_symbol, to_symbol, close from \"kamu/com.cryptocompare.ohlcv.eth-usd\"", "queryDialect": "SqlDataFusion", "dataFormat": "JsonAoa", "include": ["Input", "Proof", "Schema"], "schemaFormat": "ArrowJson", "datasets": [{ "id": "did:odf:fed0119d20360650afd3d412c6b11529778b784c697559c0107d37ee5da61465726c4", "alias": "kamu/com.cryptocompare.ohlcv.eth-usd", "blockHash": "f1620708557a44c88d23c83f2b915abc10a41cc38d2a278e851e5dc6bb02b7e1f9a1a" }], "skip": 0, "limit": 3 }, "output": { "data": [ ["2024-09-02T21:50:00Z", "eth", "usd", 2537.07], ["2024-09-02T21:51:00Z", "eth", "usd", 2541.37], ["2024-09-02T21:52:00Z", "eth", "usd", 2542.66] ], "dataFormat": "JsonAoa", "schema": {"fields": ["..."]}, "schemaFormat": "ArrowJson" }, "subQueries": [], "commitment": { "inputHash": "f1620e23f7d8cdde7504eadb86f3cdf34b3b1a7d71f10fe5b54b528dd803387422efc", "outputHash": "f1620e91f4d3fa26bc4ca0c49d681c8b630550239b64d3cbcfd7c6c2d6ff45998b088", "subQueriesHash": "f1620ca4510738395af1429224dd785675309c344b2b549632e20275c69b15ed1d210" }, "proof": { "type": "Ed25519Signature2020", "verificationMethod": "did:key:z6MkkhJQPHpA41mTPLFgBeygnjeeADUSwuGDoF9pbGQsfwZp", "proofValue": "uJfY3_g03WbmqlQG8TL-WUxKYU8ZoJaP14MzOzbnJedNiu7jpoKnCTNnDI3TYuaXv89vKlirlGs-5AN06mBseCg" } } ``` A client that gets a proof in response should perform [a few basic steps](/node/commitments#response-validation) to validate the proof integrity. For example making sure that the DID in `proof.verificationMethod` actually corresponds to the node you're querying data from and that the signature in `proof.proofValue` is actually valid. Only after this you can use this proof to hold the node accountable for the result. A proof can be stored long-term and then disputed at a later point using your own node or a 3rd party node you can trust via the `/verify` endpoint. Example request: ```json theme={null} { "input": { "query": "select event_time, from_symbol, to_symbol, close from \"kamu/com.cryptocompare.ohlcv.eth-usd\"", "queryDialect": "SqlDataFusion", "dataFormat": "JsonAoa", "include": ["Input", "Proof", "Schema"], "schemaFormat": "ArrowJson", "datasets": [{ "id": "did:odf:fed0119d20360650afd3d412c6b11529778b784c697559c0107d37ee5da61465726c4", "alias": "kamu/com.cryptocompare.ohlcv.eth-usd", "blockHash": "f1620708557a44c88d23c83f2b915abc10a41cc38d2a278e851e5dc6bb02b7e1f9a1a" }], "skip": 0, "limit": 3 }, "subQueries": [], "commitment": { "inputHash": "f1620e23f7d8cdde7504eadb86f3cdf34b3b1a7d71f10fe5b54b528dd803387422efc", "outputHash": "f1620e91f4d3fa26bc4ca0c49d681c8b630550239b64d3cbcfd7c6c2d6ff45998b088", "subQueriesHash": "f1620ca4510738395af1429224dd785675309c344b2b549632e20275c69b15ed1d210" }, "proof": { "type": "Ed25519Signature2020", "verificationMethod": "did:key:z6MkkhJQPHpA41mTPLFgBeygnjeeADUSwuGDoF9pbGQsfwZp", "proofValue": "uJfY3_g03WbmqlQG8TL-WUxKYU8ZoJaP14MzOzbnJedNiu7jpoKnCTNnDI3TYuaXv89vKlirlGs-5AN06mBseCg" } } ``` Example response: ```json theme={null} { "ok": false, "error": { "kind": "VerificationFailed::OutputMismatch", "actual_hash": "f162..c12a", "expected_hash": "f162..2a2d", "message": "Query was reproduced but resulted in output hash different from expected. This means that the output was either falsified, or the query reproducibility was not guaranteed by the system.", } } ``` See [commitments documentation](/node/commitments) for details. ## Ingesting Data Example using `curl`: ```sh theme={null} echo '[{"foo": "bar"}]' | curl -v -X POST \ 'https://api.demo.kamu.dev/account/my-dataset/ingest' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' ``` Example using `xh`: ```sh theme={null} echo '[{"foo": "bar"}]' | xh -v POST \ 'https://node.demo.kamu.dev/account/my-dataset/ingest' \ 'Authorization: Bearer ' \ 'Content-Type: application/json' ``` Content types correspond directly to [supported input formats](/cli/ingest/input-formats): | Media Type | Example | | - | - | | `text/csv` | 2020-01-01T00:01:00Z,-123.12,49.28
2020-01-01T00:02:00Z,-123.13,49.29
| | `application/json` | \[\{
"event\_time": "2020-01-01T00:01:00Z",
"long": -123.12,
"lat": 49.28
}, \{
"event\_time": "2020-01-01T00:02:00Z",
"long": -123.13,
"lat": 49.29
}]
| | `application/x-ndjson` | \{"event\_time": "2020-01-01", "long": -123.12, "lat": 49.28}
\{"event\_time": "2020-01-01", "long": -123.13, "lat": 49.29}
| | `application/geo+json` | \{
"type": "FeatureCollection",
"features": \[
\{"type": "Feature", "geometry": \{...}, "properties": \{...}},
\{"type": "Feature", "geometry": \{...}, "properties": \{...}}
]
}
| | `application/x-ndgeojson` | \{"type": "Feature", "geometry": \{...}, "properties": \{...}}
\{"type": "Feature", "geometry": \{...}, "properties": \{...}}
| | `application/vnd.apache.parquet` | binary data | | `application/vnd.esri.shapefile` | binary data | # Webhooks Source: https://docs.kamu.dev/api/webhooks **🚧 This page is under construction 🚧** Kamu Node currently support the Webhook subsciptions to modifications of a dataset. Subscriptions can be created via Web UI and GraphQL API and monitored via the "Flows" view. Webhook mechanism support payload signing according to [IETF RFC-9421](https://datatracker.ietf.org/doc/html/rfc9421). # WebSocket Source: https://docs.kamu.dev/api/websocket # About Source: https://docs.kamu.dev/cli/about
Kamu logo [Repository] | [Demo] | [Tutorials] | [Examples] | [FAQ] | [Chat]
`kamu` *(pronounced [kæmˈuː](https://en.wikipedia.org/wiki/Albert_Camus))* is a command-line tool for management and verifiable processing of dynamic structured data. It's a green-field project that aims to enable **global collaboration on data** on the same scale as seen today in software. ## Intro `kamu` is based on [Open Data Fabric](https://opendatafabric.org) protocol.

Introductory video

You can think of `kamu` as: * ***Local-first data lakehouse*** - a free alternative to Databricks / Snowflake / Microsoft Fabric that can run on your laptop without any accounts, and scale to a large on-prem cluster * ***Kubernetes for data pipelines*** - an *infrastructure-as-code* framework for building ETL pipelines using [wide range of open-source SQL engines](https://docs.kamu.dev/cli/supported-engines/) * ***Git for data*** - a tamper-proof ledger that handles data ownership and preserves full history of changes to source data * ***Blockchain for data*** - a verifiable computing system for transforming data and recording fine-grain provenance and lineage * ***Peer-to-peer data network*** - a set of [open data formats and protocols](https://github.com/open-data-fabric/open-data-fabric/) for: * Non-custodial data sharing * Federated querying of global data as if one giant database * Processing pipelines that can span across multiple organizations. ## Quick Start Use the installer script *(Linux / MacOSX / WSL2)*: ```sh theme={null} curl -s "https://get.kamu.dev" | sh ``` * Watch [introductory videos](https://www.youtube.com/watch?v=oUTiWW6W78A\&list=PLV91cS45lwVG20Hicztbv7hsjN6x69MJk) to see `kamu` in action * Follow the ["First Steps"](/start/first-steps) guide through an online demo and installation instructions. ## How it Works ### Ingest from any source `kamu` works well with popular data extractors like Debezium and provides [many built-in sources](/cli/ingest) ranging from polling data on the web to MQTT broker and blockchain logs.
Ingesting data
### Track tamper-proof history Data is stored in [Open Data Fabric](/odf) (ODF) format - an open **Web3-native format** inspired by Apache Iceberg and Delta. In addition to "table" abstraction on top of Parquet files, ODF provides: * Cryptographic integrity and commitments * Stable references * Decentralized identity, ownership, attribution, and permissions (based on [W3C DIDs](https://www.w3.org/TR/did-core/)) * Rich extensible metadata (e.g. licenses, attachments, semantics) * Compatibility with decentralized storages like [IPFS](https://ipfs.tech) Unlike Iceberg and Delta that encourage continuous loss of history through Change-Data-Capture, ODF format is **history-preserving**. It encourages working with data in the [event form](https://www.kamu.dev/blog/a-brief-history-of-time-in-data-modelling-olap-systems/), and dealing with inaccuracies through [explicit retractions and corrections](/cli/transform/retractions-corrections). ### Explore, query, document `kamu` offers a wide range of [integrations](/integrations), including: * Embedded SQL shell for quick EDA * Integrated Jupyter notebooks for ML/AI * Embedded Web UI with SQL editor and metadata explorer * Apache Superset and many other BI solutions
SQL Shell Integrated Jupyter notebook
### Build enterprise-grade ETL pipelines Data in `kamu` can only be [transformed through code](/cli/transform). An SQL query that cleans one dataset or combines two via JOIN can be used to create a **derivative dataset**. `kamu` doesn't implement data processing itself - it integrates [many popular data engines](https://docs.kamu.dev/cli/supported-engines/) *(Flink, Spark, DataFusion...)* as plugins, so you can build an ETL flow that uses the strengths of different engines at different steps of the pipeline:
Complex ETL pipeline in Kamu Web UI
### Get near real-time consistent results All derivative datasets use **stream processing** that results in some [revolutionary qualities](https://www.kamu.dev/blog/end-of-batch-era/): * Input data is only read once, minimizing the traffic * Configurable balance between low-latency and high-consistency * High autonomy - once pipeline is written it can run and deliver fresh data forever with little to no maintenance. ### Share datasets with others ODF datasets can be shared via any [conventional](https://docs.kamu.dev/cli/collab/repositories/) (S3, GCS, Azure) and [decentralized](/cli/collab/ipfs) (IPFS) storage and easily replicated. Sharing a large dataset is simple as: ```sh theme={null} kamu push covid19.case-details "s3://datasets.example.com/covid19.case-details/" ``` Because dataset **identity is an inseparable part of the metadata** - dataset can be copied, but everyone on the network will know who the owner is. ### Reuse verifiable data `kamu` will store the transformation code in the dataset metadata and ensure that it's **deterministic and reproducible**. This is a form of **verifiable computing**. You can send a dataset to someone else and they can confirm that the data they see in fact corresponds to the inputs and code: ```sh theme={null} # Download the dataset kamu pull "s3://datasets.example.com/covid19.case-details/" # Attempt to verify the transformations kamu verify --recursive covid19.case-details ``` Verifiability allows you to [establish trust](/cli/collab/validity) in data processed by someone you don't even know and detect if they act maliciously. Verifiable trust allows people to **reuse and collaborate** on data on a global scale, similarly to open-source software. ### Query world's data as one big database Through federation, data in different locations can be queried as if it was in one big data lakehouse - `kamu` will take care of how to compute results most optimally, potentially delegating parts of the processing to other nodes. Every query result is accompanied by a **cryptographic commitment** that you can use to reproduce the same query days or even months later. ### Start small and scale progressively `kamu` offers unparalleled flexibility of deployment options: * You can build, test, and debug your data projects and pipelines on a laptop * Incorporate online storage for larger volumes, but keep processing it locally * When you need real-time processing and 24/7 querying you can run the same pipelines with [`kamu-node`](/node) as a small server * A node can be deployed in Kubernetes and scale to a large cluster. ### Get data to and from blockchains Using `kamu` you can easily [read on-chain data](/cli/ingest/blockchain-source) to run analytics on smart contracts, and provide data to blockchains via novel [Open Data Fabric oracle](/api/oracle). ## Use Cases In general, `kamu` is a great fit for cases where data is exchanged between several independent parties, and for (low to moderate frequency & volume) mission-critical data where high degree of trustworthiness and protection from malicious actors is required. To share data **outside of your organization** today you have limited options: * You can publish it on some open data portal, but lose ownership and control of your data * You can deploy and operate some open-source data portal (like CKAN or Dataverse), but you probably have neither time nor money to do so * You can self-host it as a CSV file on some simple HTTP/FTP server, but then you are making it extremely hard for others to discover and use your data Let's acknowledge that for organizations that produce the most valuable data (governments, hospitals, NGOs), publishing data is **not part of their business**. They typically don't have the incentives, expertise, and resources to be good publishers. This is why the goal of `kamu` is to make data publishing **cheap and effortless**: * It invisibly guides publishers towards best data management practices (preserving history, making data reproducible and verifiable) * Adds as little friction as exporting data to CSV * Lets you host your data on any storage (S3, IPFS, GCS, FTP etc.) * Maintain full control and ownership of your data As opposed to just the download counter you get on most data portals, `kamu` brings publishers closer to the communities allowing them to see who and how uses their data. You no longer send data into "the ether", but create a **closed feedback loop** with your consumers. One of the driving forces behind `kamu`'s design was the [ongoing reproducibility crisis](https://www.nature.com/articles/533452a) in science, which we believe to a large extent is caused by our poor data management practices. After incidents like [The Surgisphere scandal](https://www.the-scientist.com/features/the-surgisphere-scandal-what-went-wrong--67955) the sentiment in research is changing from assuming that all research is done in good faith, to considering any research unreliable until proven otherwise. Data portals like Dataverse, Dryad, Figshare, and Zenodo are helping reproducibility by **archiving data**, but this approach: * Results in hundreds of millions of poorly systematized datasets * Tends to produce the research based on stale and long-outdated data * Creates lineage and provenance trail that is very manual and hard to trace (through published papers) In `kamu` we believe that the majority of valuable data (weather, census, health records, financial core data) **flows continuously**, and most of the interesting insights lie around the latest data, so we designed it to bring **reproducibility and verifiability to near real-time data**. When using `kamu`: * Your data projects are **100% reproducible** using a built-in stable references mechanism * Your results can be reproduced and **verified by others in minutes** * All the data prep work (that often accounts for [80% of time of a data scientist](https://www.forbes.com/sites/gilpress/2016/03/23/data-preparation-most-time-consuming-least-enjoyable-data-science-task-survey-says/?sh=348d5f876f63)) can be shared and **reused** by others * Your data projects will **continue to function** long after you've moved on, so the work done years ago can continue to produce valuable insights with minimal maintenance on your part * Continuously flowing datasets are much **easier to systematize** than the exponentially growing number of snapshots Data-driven journalism is on the rise and has proven to be extremely effective. In the world of misinformation and extremely polarized opinions data provides us an anchoring point to discuss complex problems and analyze cause and effect. Data itself is non-partisan and has no secret agenda, and arguments around different interpretations of data are infinitely more productive than ones based on gut feelings. Unfortunately, too often data has issues that undermine its trustworthiness. And even if the data is correct, it's very easy to pose a question about its sources that will take too long to answer - the data will be dismissed, and the gut feelings will step in. This is why `kamu`'s goal is to make data **verifiably trustworthy** and make answering **provenance** questions a **matter of seconds**. Only when data cannot be easily dismissed we will start to pay proper attention to it. And once we agree that source data can be trusted, we can build analyses and **real-time dashboards** that keep track of complex issues like corruption, inequality, climate, epidemics, refugee crises, etc. `kamu` prevents good research from going stale the moment it's published! `kamu` aims to be the most reliable data management solution that provides recent data while maintaining the **highest degree of accountability** and **tamper-proof provenance**, without you having to put all data in some central database. We're developing it with financial and pharmaceutical use cases in mind, where **audit and compliance could be fully automated** through our system. Note that we currently focus on mission-critical data and `kamu` is not well suited for IoT or other high-frequency and high-volume cases, but can be a good fit for insights produced from such data that influence your company's decisions and strategy. Being data geeks, we use `kamu` for data-driven decision-making even in our personal lives. Actually, our largest data pipelines so far were created for personal finance: * to collect and harmonize data from multiple bank accounts * convert currencies * analyze stocks trading data. We also scrape a lot of websites to make smarter purchasing decisions. `kamu` lets us keep all this data up-to-date with an **absolute minimal effort**. ## Features `kamu` connects **publishers** and **consumers** of data through a decentralized network and lets people **collaborate** on extracting insight from data. It offers many perks for everyone who participates in this first-of-a-kind data supply chain: * Easily **share your data** with the world **without moving it** anywhere * Retain full **ownership and control** of your data * Close the feedback loop and **see who and how uses your data** * Provide **real-time**, **verifiable and reproducible** data that follows the best data management practices * **Ingest any existing dataset** from the web * Always **stay up-to-date** by pulling latest updates from the data sources with just one command * Use **stable data references** to make your data projects fully reproducible * **Collaborate** on cleaning and improving data of existing datasets * Create derivative datasets by transforming, enriching, and summarizing data others have published * **Write query once and run it forever** - our pipelines require nearly zero maintenance * Built-in support for **GIS data** * **Share** your results with others in a fully reproducible and reusable form * **Download** a dataset from a shared repository * **Verify** that all data comes from trusted sources using 100% accurate **lineage** * **Audit** the chain of transformations this data went through * **Validate** that downloaded was not tampered with a single command * **Trust** your data by knowing where every single bit of information came from with our **fine grain provenance** * Explore data and run **ad-hoc SQL queries** * Launch a **Jupyter notebook** with one command * Join, filter, and shape your data using SQL * Visualize the result using your favorite library * Explore complex pipelines in Web UI ## Community If you like what we're doing - support us by [starring the repo](https://github.com/kamu-data/kamu-cli), this helps us a lot! For the list of our community resource and guides on how to contribute [start here](/community). [Repository]: https://github.com/kamu-data/kamu-cli [Demo]: /cli/demo [Tutorials]: /get-started/learning-materials [Examples]: /examples [FAQ]: /faq [Chat]: https://discord.gg/nU6TXRQNXC # Bad Data on Ingestion Source: https://docs.kamu.dev/cli/bad-data/ingest-errors # PII and Sensitive Data Source: https://docs.kamu.dev/cli/bad-data/pii # Retractions & Corrections Source: https://docs.kamu.dev/cli/bad-data/retractions-corrections # Bad Data in Upstream Datasets Source: https://docs.kamu.dev/cli/bad-data/upstream # Sharing & Collaboration Source: https://docs.kamu.dev/cli/collab/index While `kamu` is a very powerful tool for managing and processing data on your own computer, the real power of it becomes apparent only when you start exchanging data with other people. Thanks to its core properties it makes sharing data reliable and safe both within your organization and between multiple completely independent parties. # Sharing datasets with IPFS Source: https://docs.kamu.dev/cli/collab/ipfs Describes integration with content-addressable decentralized storage The `kamu` and [IPFS](https://ipfs.io/) (The Interplanetary File System) projects have overlapping goals - preserving and growing humanity's knowledge. While IPFS focuses on storing files (objects), `kamu`'s focus is on structured data and dynamic data processing, but under the hood even a real-time dataset in `kamu` is just a set of files! Below we show how `kamu` builds on top of many similar concepts as IPFS and how IPFS can be used as a very efficient **storage layer** for sharing your datasets and pipelines with the world. ## IPFS Basics The IPFS is well-documented, so we will quickly review the basics, and if you find any of them confusing simply follow the links: * IPFS is **decentralized** * You are fully responsible for your own data's persistence, replication, and availability ([more](https://docs.ipfs.io/concepts/persistence/)) * To publish data you need to run a node ([more](https://docs.ipfs.io/concepts/nodes/)) * To read data you can use your node or a public IPFS Gateway ([more](https://docs.ipfs.io/concepts/ipfs-gateway/)) * IPFS is a **content-addressable** storage ([more](https://docs.ipfs.io/concepts/content-addressing/)) * The IPFS URL is based on a CID (content identifier) which is derived from a hash sum of the data it points to ([more](https://docs.ipfs.io/concepts/hashing/)) * Every time the content of a file changes you get a **different URL** * Old and new file are different objects - the data in IPFS is **immutable** ([more](https://docs.ipfs.io/concepts/immutability/)) * **Mutability can be simulated** with special URLs that can point to different CIDs at different times * Currently supported naming mechanisms are [IPNS](https://docs.ipfs.io/concepts/ipns/) and [DNSLink](https://docs.ipfs.io/concepts/dnslink/) * IPNS uses a hashsum of a public key to create a unique name entry in a decentralized way ([more](https://docs.ipfs.io/concepts/ipns/)). ## Kamu and IPFS Unlike any other data processing system, `kamu` was build from ground up with reproducibility in mind - it defaults to never losing history. As the [ODF spec](/odf/spec/overview) explains in detail - the best way to do this is to represent data as **append-only** event streams. These event streams are represented by a linked list of metadata blocks (think git history or blockchain) that reference portions of raw data and checkpoint files: So, very similarly to IPFS, the composing parts of a dataset in `kamu` are: * **Immutable** - dataset only changes by appending new blocks * **Content-addressable** - a metadata block, data file, or a checkpoint are uniquely identified by their hashsum Why it matters? Imagine you store a directory containing many large files in IPFS and it is assigned `CID1`. When you add a new file to it and do `ipfs add . -r` again IPFS will notice that it already has CIDs for all but one file and will reuse those objects: If `CID1` remains "pinned" it basically represents the state of the same directory as `CID2` but at the previous point in time. This also works for `kamu` datasets: * Each time you push to IPFS you are only adding the blocks and objects that were not seen previously. There is no duplication. * Previous CIDs remain valid - they simply point to an older subset of an event stream. * Having just one "pointer" to a metadata block you can "walk" the entire metadata chain and discover all dataset components. Unlike many other data processing systems that mutate data, the cheapness of an "append" operation in `kamu` allows it achieve near real-time latencies of data propagation even when handling massive datasets and using immutable storage like IPFS. The above diagrams are good to build up some intuition, but this is not exactly how data looks like in IPFS on the [IPLD DAG](https://ipld.io/) level. An accurate diagram would need to consider: * Slicing of large files into multiple objects * Raw vs. wrapped nodes * Balanced vs. custom DAG structure ## Pulling from IPFS `kamu` supports pulling data from IPFS just like from any [other repository](/cli/collab/repositories). You can use both `ipfs://` and `ipns://` URLs: ```bash theme={null} kamu pull ipfs://bafybeietcz4lxovy3ejdhb67nt3lj43vaeuyhectkqfnmmlnatfug5vqhe --as my-dataset --no-alias kamu pull ipns://k51qzi5uqu5dic6zu9i2f4afctxmsm298ypiuy3ijmob1w6m96c092qp4ev7mn --as my-dataset ``` Since the content behind an `ipfs://` URL never changes we use `--no-alias` flag to skip creation of the pull alias. ### Configuring IPFS Gateway Under the hood `kamu` will use the configured IPFS Gateway to fetch data converting the URL into something like `http(s)://{gateway}/ipfs/{cid}` or `http(s)://{gateway}/ipns/{key}`. By default it will try to use your local IPFS daemon as a gateway. You can see this by running: ```bash theme={null} kamu config get --with-defaults protocol.ipfs.httpGateway > "http://localhost:8080/" ``` If you only read data from IPFS and not planning to write - you can avoid running an IPFS daemon by switching to one of the [public IPFS Gateways](https://ipfs.github.io/public-gateway-checker/): ```bash theme={null} kamu config set --user protocol.ipfs.httpGateway "https://dweb.link/" ``` ## Pushing to IPFS Clearly, pushing to an `ipfs://` URL will not work as we don't know the CID upfront, not until all data has been hashed: ```bash theme={null} kamu push my-dataset --to ipfs:// ``` We need a URL that remains stable when the underlying dataset is updated - we can use [IPNS](https://docs.ipfs.io/concepts/ipns/) for this. IPNS is like a named pointer to a CID that can be re-pointed to a different CID only by its owner. To create unique collision-free names in a decentralized way and to have a way for you to prove ownership of this name at the same time IPNS is using cryptographic key pairs: * A public/private key pair is generated * Name is derived by hashing the public key * Private key is used for signing publishing requests to prove that you are the owner of said name. To push data to IPFS you will need a local IPFS daemon running. We first generate a new key pair that we will use for our dataset: ```bash theme={null} ipfs key gen my-dataset > k51qzi5uqu5dgl4gf3uayepenee5tzix3r8oiwyimxsfuikr7alq928xxtwmew ``` We can now use this key to form a destination URL as `ipns://{key}` and push the dataset: ```bash theme={null} kamu push my-dataset --to ipns://k51qzi5uqu5dgl4gf3uayepenee5tzix3r8oiwyimxsfuikr7alq928xxtwmew ``` Currently IPNS keys have a default lifetime of 24h (see `ipfs name publish --help`). This means you'll need to run push command periodically (e.g. on a cron job) to prevent it from expiring. Otherwise your URL will become non-resolvable. Since IPNS pointers are mutable the next time we update the dataset we can push it again using the push alias `kamu` created for us: ```bash theme={null} # Update the dataset locally kamu pull my-dataset > # Push updates via IPNS push alias kamu push my-dataset > Syncing dataset (my-dataset > ipns://k51q...wmew) > Updated to (1 block(s)) ``` And that's all there is to it! You now have all the basic building blocks to create **fully decentralized data pipelines**, both on storage and compute levels! # Privacy and Permissions Source: https://docs.kamu.dev/cli/collab/privacy-and-permissions # Provenance Source: https://docs.kamu.dev/cli/collab/provenance # Repositories Source: https://docs.kamu.dev/cli/collab/repositories Describes different approaches to sharing datasets ## Supported Repository Types Data in `kamu` is shared via . There are multiple types of repositories that differ by the kinds of services they provide. The most basic repository allows you to upload ("push") and download ("pull") data, while more advanced can allow searching datasets, query data in-place, or subscribing for updates. | Type | Description | Capabilities | URL Examples | | :-: | - | :-: | - | | Local FS | A basic repository that uses the local file system folder. Mainly used for examples and testing. | `pull`
`push` | `file:///home/me/example/repository`
`file:///c:/Users/me/example/repository` | | HTTP(s) | A basic repository that provides read-only access to data. | `pull` | `https://example.org/dataset` | | S3 | A basic repository that stores data in Amazon S3 bucket. Can be used with any S3-compatible storage API | `pull`
`push` | `s3://bucket.my-company.example`
`s3+http://my-minio-server:9000/bucket`
`s3+https://my-minio-server:9000/bucket` | | IPFS | Uses IPFS HTTP Gateway for reading. Push is only possible via IPNS (see [details](/cli/collab/ipfs)). | `pull`
`push` | `ipfs://bafy...vqhe`
`ipns://k51q...v7mn` | | ODF | ODF-native repositories types that support very fast data transfer and querying data in-place | `pull`
`push`
`query`
`search` | `odf+http://odf.acme.com`
`odf+https://kamu.dev` | ## Push / Pull Aliases Starting out, you can always use explicit URLs when syncing data from and to repositories. If some remote source contains a dataset you're interested in you can download it using the `pull` command: ```bash theme={null} kamu pull https://example.org/dataset --as example-dataset ``` If you have a dataset you would like to share, or made some changes to a dataset you are sharing with your friends - you can upload the new data using the `push` command: ```bash theme={null} kamu push example-dataset --to s3://my-bucket.example.org/example-dataset ``` When you run these commands, `kamu` will automatically create "pull" and "push aliases" for this dataset: ```bash theme={null} kamu repo alias list example-dataset ``` ``` ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │ Dataset │ Kind │ Alias │ ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤ │ example-dataset │ Pull │ https://example.org/dataset │ │ example-dataset │ Push │ s3://my-bucket.example.org/example-dataset │ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ ``` With aliases in place, next time you want to pull or push data you can simply do: ```bash theme={null} kamu pull example-dataset # Will pull from https://example.org/dataset kamu push example-dataset # Will push to s3://my-bucket.example.org/example-dataset ``` Both `pull` and `push` commands will analyze the state of the dataset in the and at the repository and will only upload data and metadata that wasn't previously seen (a minimal update). These commands are also "safe". They will detect all types of concurrent changes and history divergence and prevent you from overwriting someone else's changes. When you pull a `Root` dataset from a remote source running `kamu pull` on it will attempt to sync it from the repository, and NOT execute a polling or other ingest action. In `kamu list` datasets with pull aliases will be showing up as `Remote(...)`. ## Repositories If you store multiple datasets side by side in some locations you can add it as a repository. Repositories are configured per using the `kamu repo` command group. To add new repo use: ```bash theme={null} kamu repo add my-s3-bucket s3://my-bucket.example.org/ ``` This repo will now be visible in `kamu repo list`. To pull/push a dataset from/to this repo you can now use remote references like `/`: ```bash theme={null} kamu pull my-s3-bucket/example-dataset kamu push example-dataset --to my-s3-bucket ``` ## Searching for Data To look for datasets in the repos use: ```bash theme={null} kamu search covid19 # Searching with empty query lists (a limited number of) datasets in all repos kamu search # You can specify the search term and specific repo to look in kamu search covid19 --repo my-s3-bucket ``` Search is delegated to the repository implementations and its capabilities depend on the type of the repo. Whereas smart repos may support advanced full-text search, simple storage-only repos may be limited to a substring search by dataset name. # Validity of Data Source: https://docs.kamu.dev/cli/collab/validity Describes audit and verification procedures that can be used to ensure the data presented to you is trustworthy This topic is also covered in detail in this video: With `kamu` sharing data becomes very easy, but with that problem out of the way you will soon start wondering "How can I trust the data I downloaded from someone else?". Let's first define what validity or trustworthiness of data means. For a more technical description see . ### Validity of Root Data Let's say you're about to use a root dataset containing historical weather information in your city. How can you be sure it's trustworthy? Because source data is non-reproducible, its validity depends entirely on its publisher. Publisher is in full control of the data they present, which also means that measuring and processing errors and even malicious data can easily make its way into the root dataset. Make sure that your publishers have good reputation and prefer data that comes from well-established organizations (government or NGOs) that directly collect or operate the systems from which the data is gathered. Aside from external audits, another way to improve confidence in data is to correlate it with data from other similar sources. In our example we could compare it with the data from a weather station in the neighboring city and look for anomalies. ### Validity of Derivative Data Derivative data in `kamu` is created purely through transformations that are recorded in metadata. These transformations can still be malicious, but since they are usually small (e.g. a few SQL queries) we can easily audit them to ensure they are sound and done in good faith. Repeating this process for the entire transformation chain, starting with root datasets, will give you confidence in trustworthiness of derivative data. ### Verifying Validity Based on the above, here are the steps needed to ensure a dataset is trustworthy: * Inspect lineage and identify all root datasets it's composed of * Ensure publishers of root datasets are reputable and credible * Use lineage to audit all derivative transformations to see if they are sound and non-malicious * Use `kamu verify` command to ensure that data you downloaded actually matches the declared transformations Example: ```bash theme={null} # Inspect the dependency graph of a dataset to find all root sources kamu inspect lineage ca.vancouver.opendata.weather.aggregated-daily # Inspect the transformations applied # Repeat this for every derivative dataset in the dependency graph kamu inspect query ca.vancouver.opendata.weather.aggregated-daily # Verify the data matches the declared metadata and transformations kamu verify --recursive ca.vancouver.opendata.weather.aggregated-daily ``` For every derivative dataset the `kamu verify` command does two things: * Compares hashes of data you downloaded to the ones stored in metadata (ensures data is not tampered or corrupted) * Executes the declared derivative transformations locally to compare the hash of the result to one stored in metadata (ensures that metadata was not spoofed to match the fake result) Remember that in the fight for data validity you are not alone. Other people will also be verifying these datasets, so the Open Data Fabric network can quickly detect and exclude the participants who distribute malicious data. # Commands Reference Source: https://docs.kamu.dev/cli/commands ## `kamu` **Usage:** `kamu [OPTIONS] ` **Subcommands:** * `add` — Add a new dataset or modify an existing one * `apply` — Create or update resources from manifest files * `completions` — Generate tab-completion scripts for your shell * `config` — Get or set configuration options * `context [ctx]` — Manage resource contexts * `delete [rm]` — Delete datasets or resources * `export` — Exports a dataset * `get` — Returns manifest representation of a resource * `ingest` — Adds data to the root dataset according to its push source configuration * `init` — Initialize an empty workspace in the current directory * `inspect` — Group of commands for exploring dataset metadata * `list [ls]` — List datasets or resources * `log` — Shows dataset metadata history * `login` — Authenticates with a remote ODF server interactively * `logout` — Logs out from a remote Kamu server * `new` — Creates a new dataset manifest from a template * `notebook` — Starts the notebook server for exploring the data in the workspace * `pull` — Pull new data into the datasets * `push` — Push local data into a repository * `rename [mv]` — Rename a dataset * `reset` — Revert the dataset back to the specified state * `repo` — Manage set of tracked repositories * `search` — Searches for datasets in the registered repositories * `sql` — Executes an SQL query or drops you into an SQL shell * `summary` — Show resource summary for the active context * `system` — Command group for system-level functionality * `tail` — Displays a sample of most recent records in a dataset * `ui` — Opens web interface * `verify` — Verifies the validity of a dataset * `version` — Outputs build information **Options:** * `-v` — Sets the level of verbosity (repeat for more) * `--no-color` — Disable color output in the terminal * `-q`, `--quiet` — Suppress all non-essential output * `-y`, `--yes` — Do not ask for confirmation and assume the 'yes' answer * `--trace` — Record and visualize the command execution as perfetto.dev trace * `--show-error-stack-trace` — Show stack trace in case of a command execution error * `--metrics` — Dump all metrics at the end of command execution To get help for individual commands, use: kamu \ -h kamu \ \ -h ## `kamu add` Add a new dataset or modify an existing one **Usage:** `kamu add [OPTIONS] [MANIFEST]...` **Arguments:** * `` — Dataset manifest reference(s) (path, or URL) **Options:** * `-r`, `--recursive` — Recursively search for all manifest in the specified directory * `--replace` — Delete and re-add datasets that already exist * `--stdin` — Read manifests from standard input * `--name ` — Overrides the name in a loaded manifest * `--visibility ` — Changing the visibility of the added dataset Possible values: `private`, `public` This command creates a new dataset from the provided DatasetSnapshot manifest. Note that after kamu creates a dataset the changes in the source file will not have any effect unless you run the add command again. When you are experimenting with adding new dataset you currently may need to delete and re-add it multiple times until you get your parameters and schema right. In future versions the add command will allow you to modify the structure of already existing datasets (e.g. changing schema in a compatible way). **Examples:** Add a root/derivative dataset from local manifest: kamu add org.example.data.yaml Add datasets from all manifests found in the current directory: kamu add --recursive . Add a dataset from manifest hosted externally (e.g. on GihHub): kamu add [https://raw.githubusercontent.com/kamu-data/kamu-contrib/master/ca.bankofcanada/ca.bankofcanada.exchange-rates.daily.yaml](https://raw.githubusercontent.com/kamu-data/kamu-contrib/master/ca.bankofcanada/ca.bankofcanada.exchange-rates.daily.yaml) To add dataset from a repository see `kamu pull` command. ## `kamu apply` Create or update resources from manifest files **Usage:** `kamu apply [OPTIONS] [PATH]...` **Arguments:** * `` — Manifest file or directory path(s) **Options:** * `-c`, `--context ` — Override the current resource context for this invocation * `--dry-run` — Preview the accepted changes without applying them * `--format ` — Parse all selected files using the specified manifest format Possible values: `json`, `yaml` * `-r`, `--recursive` — Recursively scan directories for manifests * `--stdin` — Read manifest from standard input * `--continue-on-error` — Apply each manifest independently instead of the batch as a single all-or-nothing transaction, so earlier successes survive a later manifest's rejection or failure Applies one or more resource manifests to the active resource context. If the active context is `local`, manifests are applied to the current workspace. If the active context points to a remote server, manifests are applied through the remote GraphQL API. Use `--dry-run` to preview the accepted changes without applying them. By default, a multi-manifest batch is applied atomically: if any manifest is rejected or fails, the entire batch is rolled back, including manifests earlier in the batch that would otherwise have succeeded. Use `--continue-on-error` to instead apply each manifest independently, so that earlier successes are kept even if a later manifest fails. **Examples:** Apply a single manifest: kamu apply my-resource.yaml Preview changes without applying them: kamu apply my-resource.yaml --dry-run Apply all manifests in a directory recursively: kamu apply manifests/ --recursive Apply multiple files in the given order: kamu apply a.yaml b.json Apply a manifest from standard input: cat my-resource.yaml | kamu apply --stdin Force JSON parsing regardless of file extension: kamu apply generated.resource --format json ## `kamu completions` Generate tab-completion scripts for your shell **Usage:** `kamu completions ` **Arguments:** * `` Possible values: `bash`, `elvish`, `fish`, `powershell`, `zsh` The command outputs to STDOUT, allowing you to re-direct the output to the file of your choosing. Where you place the file will depend on which shell and which operating system you are using. Your particular configuration may also determine where these scripts need to be placed. Here are some common set ups: **Bash:** Append the following to your `~/.bashrc`: source \<(kamu completions bash) You will need to reload your shell session (or execute the same command in your current one) for changes to take effect. **Zsh:** Append the following to your `~/.zshrc`: autoload -U +X bashcompinit && bashcompinit source \<(kamu completions bash) Please contribute a guide for your favorite shell! ## `kamu config` Get or set configuration options **Usage:** `kamu config ` **Subcommands:** * `list [ls]` — Display current configuration combined from all config files * `get` — Get current configuration value * `set` — Set or unset configuration value Configuration in `kamu` is managed very similarly to `git`. Starting with your current workspace and going up the directory tree you can have multiple `.kamuconfig` YAML files which are all merged together to get the resulting config. Most commonly you will have a workspace-scoped config inside the `.kamu` directory and the user-scoped config residing in your home directory. **Examples:** List current configuration as combined view of config files: kamu config list Get current configuration value: kamu config get engine.runtime Set configuration value in workspace scope: kamu config set engine.runtime podman Set configuration value in user scope: kamu config set --user engine.runtime podman Unset or revert to default value: kamu config set --user engine.runtime ## `kamu config list` Display current configuration combined from all config files **Usage:** `kamu config list [OPTIONS]` **Options:** * `--scope ` — Which configs to use Default value: `combined` Possible values: * `user`: Includes only config in user home directory * `workspace`: Includes only current workspace config * `combined`: Includes configs in workspace, parent directories, and user home dir * `--user` — Show only user scope configuration * `--with-defaults` — Show configuration with all default values applied * `-o`, `--output-format ` — Serialization format of the returned object Default value: `yaml` Possible values: `yaml`, `json` ## `kamu config get` Get current configuration value **Usage:** `kamu config get [OPTIONS] [CFGKEY]` **Arguments:** * `` — Path to the config option **Options:** * `--scope ` — Which configs to use Default value: `combined` Possible values: * `user`: Includes only config in user home directory * `workspace`: Includes only current workspace config * `combined`: Includes configs in workspace, parent directories, and user home dir * `--user` — Operate on the user scope configuration file * `--with-defaults` — Get default value if config option is not explicitly set * `-o`, `--output-format ` — Serialization format of the returned object Default value: `yaml` Possible values: `yaml`, `json` ## `kamu config set` Set or unset configuration value **Usage:** `kamu config set [OPTIONS] [VALUE]` **Arguments:** * `` — Path to the config option * `` — New value to set **Options:** * `--scope ` — Which configs to consider Default value: `combined` Possible values: * `user`: Includes only config in user home directory * `workspace`: Includes only current workspace config * `combined`: Includes configs in workspace, parent directories, and user home dir * `--user` — Operate on the user scope configuration file * `-i`, `--input-format ` — Serialization format of the provided object Default value: `yaml` Possible values: `yaml`, `json` ## `kamu context` Manage resource contexts **Usage:** `kamu context [NAME] context ` **Subcommands:** * `add` — Register a new remote resource context * `list [ls]` — List configured resource contexts * `delete [rm]` — Delete a remote resource context * `check` — Check connectivity and authorization for a remote resource context * `api-resources` — List supported resource types in the active context * `use` — Switch the current resource context **Arguments:** * `` — Context name to switch to Contexts determine which workspace future resource commands will target. When running inside a workspace, an implicit local context named `local` is available automatically whenever no current context is selected. You can still select `local` explicitly. Remote contexts can be registered either in the workspace or in the user home scope. **Examples:** Show current context: kamu context List configured contexts: kamu context ls Check a remote context: kamu context check demo Refresh cached status for all remote contexts: kamu context check --all Switch to a context: kamu context prod Switch back to the local workspace context: kamu context local Register a workspace-scoped remote context: kamu context add prod --url [https://api.kamu.dev](https://api.kamu.dev) Register a user-scoped remote context: kamu context add prod --url [https://api.kamu.dev](https://api.kamu.dev) --user Register a remote context non-interactively with an existing token: kamu context add prod --url [https://api.kamu.dev](https://api.kamu.dev) --access-token \ List supported resource types in the active context: kamu ctx api-resources List supported resource types from a specific context: kamu ctx api-resources --context prod ## `kamu context add` Register a new remote resource context **Usage:** `kamu context add [OPTIONS] --url ` **Arguments:** * `` — Context name **Options:** * `--user` — Store context in the user home folder rather than in the workspace * `--url ` — Backend URL of the remote workspace * `--access-token ` — Provide an existing access token instead of logging in * `--password-login ` — User name for non-interactive password login * `--password ` — Password for non-interactive password login * `--oauth-provider ` — Name of the OAuth provider for non-interactive login, i.e. 'github' * `--oauth-token ` — OAuth provider access token * `--no-login` — Do not attempt to log in, only register the context * `--repo-name ` — Repository name which will be used to store in repositories list * `--skip-add-repo` — Don't automatically add a remote repository for this host Registers a remote workspace context under a local name. By default the context is stored in the current workspace. Use `--user` to store it in the user home scope instead. The name `local` is reserved for the implicit workspace context and cannot be registered explicitly. If no access token is stored for the given URL, the interactive browser login flow is started automatically, provided the session is an interactive terminal. In non-interactive sessions (CI, scripts) the context is only registered and a warning is printed. Use the credential arguments below to authenticate non-interactively, or `--no-login` to skip authentication entirely. **Examples:** Add a workspace-scoped remote context, logging in interactively if needed: kamu context add prod --url [https://example.com](https://example.com) Add a user-scoped remote context: kamu context add prod --url [https://example.com](https://example.com) --user Add a context using an existing access token: kamu context add prod --url [https://example.com](https://example.com) --access-token \ Add a context with non-interactive password login: kamu context add prod --url [https://example.com](https://example.com) --password-login alice --password s3cret Add a context with non-interactive OAuth login: kamu context add prod --url [https://example.com](https://example.com) --oauth-provider github --oauth-token \ Register a context without authenticating: kamu context add prod --url [https://example.com](https://example.com) --no-login ## `kamu context list` List configured resource contexts **Usage:** `kamu context list [OPTIONS]` **Options:** * `-o`, `--output-format ` — Format to display the results in Possible values: * `csv`: Comma-separated values * `json`: Array of Structures format * `ndjson`: One Json object per line - easily splittable format * `json-soa`: Structure of arrays - more compact and efficient format for encoding entire dataframe * `json-aoa`: Array of arrays - compact and efficient and preserves column order * `table`: A pretty human-readable table * `parquet`: Parquet columnar storage. Only available when exporting to file(s) Lists effective resource contexts configured in the workspace and user scopes. When running inside a workspace, the implicit `local` context is also included. **Examples:** List contexts: kamu context ls List contexts in JSON: kamu context ls -o json ## `kamu context delete` Delete a remote resource context **Usage:** `kamu context delete [OPTIONS] [NAME]` **Arguments:** * `` — Context name **Options:** * `--user` — Delete context from the user home folder rather than in the workspace * `--all` — Delete all remote contexts in the selected scope Deletes a previously registered remote context from the selected scope. By default deletion happens in the current workspace. Use `--user` to delete a user-scoped context instead. Use `--all` to delete all remote contexts from the selected scope. The name `local` is reserved and cannot be deleted. **Examples:** Delete a workspace-scoped context: kamu context delete prod Delete a user-scoped context: kamu context delete prod --user Delete all workspace-scoped remote contexts: kamu context rm --all ## `kamu context check` Check connectivity and authorization for a remote resource context **Usage:** `kamu context check [OPTIONS] [NAME]` **Arguments:** * `` — Context name **Options:** * `--all` — Check all effective remote contexts Checks backend reachability and access token validity for a context. If no context name is provided, the effective current context is checked. Use `--all` to refresh cached status for all configured remote contexts. **Examples:** Check a named context: kamu context check demo Check the current context: kamu context check Check all remote contexts: kamu context check --all ## `kamu context api-resources` List supported resource types in the active context **Usage:** `kamu context api-resources [OPTIONS]` **Options:** * `-c`, `--context ` — Override the current resource context for this invocation * `-o`, `--output-format ` — Format to display the results in Possible values: * `csv`: Comma-separated values * `json`: Array of Structures format * `ndjson`: One Json object per line - easily splittable format * `json-soa`: Structure of arrays - more compact and efficient format for encoding entire dataframe * `json-aoa`: Array of arrays - compact and efficient and preserves column order * `table`: A pretty human-readable table * `parquet`: Parquet columnar storage. Only available when exporting to file(s) Lists resource types supported by the active context. If the active context is `local`, this targets the current workspace. If the active context points to a remote server, this targets that remote GraphQL API. Use `--context` to override the current context for this invocation only. **Examples:** List supported resource types in the active context: kamu ctx api-resources List supported resource types from a specific context: kamu ctx api-resources --context prod List supported resource types in JSON: kamu ctx api-resources -o json ## `kamu context use` Switch the current resource context **Usage:** `kamu context use ` **Arguments:** * `` — Context name Switches the current resource context to the specified named remote context. This is the explicit form of `kamu context `. The special name `local` refers to the current workspace when one is available. **Examples:** Switch to a context: kamu context use prod Switch to the local workspace context: kamu context use local ## `kamu delete` Delete datasets or resources **Usage:** `kamu delete [OPTIONS] [TARGET] [ARGS]...` **Arguments:** * `` — Target to delete: `datasets`, `%` (all resource types), or a resource selector such as `variablesets`, `vs`, `secretsets`, `ss`, `storages`, or `st` * `` — Dataset selector(s) in dataset mode, or a single resource selector in resource mode **Options:** * `-c`, `--context ` — Override the current resource context for this invocation * `-a`, `--all` — Delete all matched datasets or all resources in the selected scope * `-r`, `--recursive` — Also delete all transitive dependencies of specified datasets * `-f`, `--force` — Do not ask for confirmation * `--ignore-not-found` — Exit successfully when a selected resource does not exist * `--dry-run` — Preview the resolved resource deletions without deleting anything * `-l`, `--label ` — Narrow the selection to resources carrying all of the given labels, as `key=value` pairs (repeatable, or comma-separated) This command deletes datasets using the legacy dataset path by default, or resources when a resource target is specified explicitly. **Examples:** Delete a local dataset using the legacy default: kamu delete my.dataset Delete datasets explicitly: kamu delete datasets my.dataset Delete a dataset using the dataset pseudo-type selector: kamu delete dataset/my.dataset Delete local datasets matching a pattern: kamu delete my.dataset.% Delete a single resource: kamu delete storages warehouse Delete same-type resources by name pattern: kamu delete vs app-% Delete all resources of a type: kamu delete storages --all Delete all resources across types: kamu delete '%/%' Delete resources using slash selectors: kamu delete vs/my-vars ss/my-secrets Delete the same exact name across every resource type: kamu delete % db-creds Delete resources matching a name pattern across every resource type: kamu delete %/db-% Delete all resources of a type using a slash selector: kamu delete 'storages/%' Delete a dataset and a resource in one command: kamu delete dataset/my.dataset vs/my-vars Force dataset interpretation when a dataset account collides with a resource prefix: kamu delete datasets vs/my.dataset Preview deletion: kamu delete dataset/my.dataset vs/my-vars --dry-run Narrow a deletion to resources carrying a label: kamu delete variablesets --all -l environment=stale --dry-run ## `kamu export` Exports a dataset **Usage:** `kamu export [OPTIONS] --output-format ` **Arguments:** * `` — Local dataset reference **Options:** * `--output-path ` — Export destination. Dafault is `/` * `--output-format ` — Output format * `--records-per-file ` — Number of records per file, if stored into a directory. It's a soft limit. For the sake of export performance the actual number of records may be slightly different This command exports a dataset to a file or set of files of a given format. Output path may be either file or directory. When a path contains extention, and no trailing separator, it is considered as a file. In all other cases a path is considered as a directory. Examples: * `export/dataset.csv` is a file path * `export/dataset.csv/` is a directory path * `export/dataset/` is a directory path * `export/dataset` is a directory path ## `kamu get` Returns manifest representation of a resource **Usage:** `kamu get [OPTIONS] [ARGS]...` **Arguments:** * `` — Resource selector(s): `type name...` or `type/name...` **Options:** * `-c`, `--context ` — Override the current resource context for this invocation * `-o`, `--output-format ` — Serialization format of the returned object Default value: `yaml` Possible values: `json`, `name`, `yaml` * `--spec` — Return an apply-compatible spec manifest instead of the full resource view * `--revealed` — Show actual secret values in the output (decrypts encrypted fields). Cannot be used with `-o name` * `--ignore-not-found` — Exit successfully when the resource does not exist * `--max-results ` — Maximum number of resources resolved by expanding selectors Default value: `100` * `--unbounded` — Disable the limit for expanding selectors * `-l`, `--label ` — Narrow the selection to resources carrying all of the given labels, as `key=value` pairs (repeatable, or comma-separated) Returns the current state of one or more resources as YAML or JSON. Only real resource types supported by the active context are accepted. Datasets are intentionally not supported by this command. By default this command returns the full resource view, including status. Use `--spec` to return the apply-compatible spec manifest instead. When multiple selectors are provided, the output is wrapped in an `items` list. **Examples:** Get a variable set manifest in YAML: kamu get variablesets my-vars Get the same resource in JSON: kamu get vs my-vars -o json Get the apply-compatible spec manifest: kamu get vs my-vars --spec Get multiple resources of the same type: kamu get variablesets vars-a vars-b Get same-type resources by name pattern: kamu get vs app-% Get multiple resources by slash-separated ref form: kamu get vs/vars-a ss/db-creds Get the same exact name across every resource type: kamu get % db-creds Get resources matching a name pattern across every resource type: kamu get %/db-% Get every resource of every type: kamu get '%/%' Get a resource by UUID: kamu get variablesets 3d8d6d1c-6f7c-4c62-9f4e-7d8295e8fb69 Read a resource from a remote context: kamu get storages warehouse --context prod Ignore missing resources: kamu get secretsets missing-a missing-b --ignore-not-found Narrow matched resources to those carrying a label: kamu get 'variablesets/%' -l environment=production ## `kamu ingest` Adds data to the root dataset according to its push source configuration **Usage:** `kamu ingest [OPTIONS] [FILE]...` **Arguments:** * `` — Local dataset reference * `` — Data file(s) to ingest **Options:** * `--source-name ` — Name of the push source to use for ingestion * `--event-time ` — Event time to be used if data does not contain one * `--stdin` — Read data from the standard input * `-r`, `--recursive` — Recursively propagate the updates into all downstream datasets * `--input-format ` — Overrides the media type of the data expected by the push source Possible values: `csv`, `json`, `ndjson`, `geojson`, `ndgeojson`, `parquet`, `esrishapefile` **Examples:** Ingest data from files: kamu ingest org.example.data path/to/data.csv Ingest data from standard input (assumes source is defined to use NDJSON): echo '\{"key": "value1"}\n\{"key": "value2"}' | kamu ingest org.example.data --stdin Ingest data with format conversion: echo '\[\{"key": "value1"}, \{"key": "value2"}]' | kamu ingest org.example.data --stdin --input-format json Ingest data with event time hint: kamu ingest org.example.data data.json --event-time 2050-01-02T12:00:00Z ## `kamu init` Initialize an empty workspace in the current directory **Usage:** `kamu init [OPTIONS]` **Options:** * `--exists-ok` — Don't return an error if workspace already exists * `--pull-images` — Only pull container images and exit A workspace is where kamu stores all the important information about datasets (metadata) and in some cases raw data. It is recommended to create one kamu workspace per data science project, grouping all related datasets together. Initializing a workspace creates a `.kamu` directory contains dataset metadata, data, and all supporting files (configs, known repositories etc.). ## `kamu inspect` Group of commands for exploring dataset metadata **Usage:** `kamu inspect ` **Subcommands:** * `lineage` — Shows the dependency tree of a dataset * `query` — Shows the transformations used by a derivative dataset * `schema` — Shows the dataset schema ## `kamu inspect lineage` Shows the dependency tree of a dataset **Usage:** `kamu inspect lineage [OPTIONS] [DATASET]...` **Arguments:** * `` — Local dataset reference(s) **Options:** * `-o`, `--output-format ` — Format of the output Possible values: `shell`, `dot`, `csv`, `html` * `-b`, `--browse` — Produce HTML and open it in a browser Presents the dataset-level lineage that includes current and past dependencies. **Examples:** Show lineage of a single dataset: kamu inspect lineage my.dataset Show lineage graph of all datasets in a browser: kamu inspect lineage --browse Render the lineage graph into a png image (needs graphviz installed): kamu inspect lineage -o dot | dot -Tpng > depgraph.png ## `kamu inspect query` Shows the transformations used by a derivative dataset **Usage:** `kamu inspect query ` **Arguments:** * `` — Local dataset reference This command allows you to audit the transformations performed by a derivative dataset and their evolution. Such audit is an important step in validating the trustworthiness of data (see `kamu verify` command). ## `kamu inspect schema` Shows the dataset schema **Usage:** `kamu inspect schema [OPTIONS] ` **Arguments:** * `` — Local dataset reference **Options:** * `-o`, `--output-format ` — Format of the output Default value: `odf-yaml` Possible values: `arrow-json`, `ddl`, `odf-json`, `odf-yaml`, `parquet`, `parquet-json` Displays the schema of the dataset. Note that dataset schemas can evolve over time and by default the latest schema will be shown. **Examples:** Show logical schema of a dataset in the ODF format: kamu inspect schema my.dataset Show physical schema of the underlying Parquet files: kamu inspect schema my.dataset -o parquet ## `kamu list` List datasets or resources **Usage:** `kamu list [OPTIONS] [TARGETS]...` **Arguments:** * `` — Targets to list: `datasets`, `%` (all resource types), a resource selector such as `variablesets`, `vs`, `secretsets`, `ss`, `storages`, or `st`, optionally narrowed as `type/name`, `type/pattern-%` or `type/`. Several resource selectors may be given at once **Options:** * `-c`, `--context ` — Override the current resource context for this invocation * `-o`, `--output-format ` — Format to display the results in Possible values: * `csv`: Comma-separated values * `json`: Array of Structures format * `ndjson`: One Json object per line - easily splittable format * `json-soa`: Structure of arrays - more compact and efficient format for encoding entire dataframe * `json-aoa`: Array of arrays - compact and efficient and preserves column order * `table`: A pretty human-readable table * `parquet`: Parquet columnar storage. Only available when exporting to file(s) * `-w`, `--wide` — Show more details (repeat for more) * `--max-results ` — Maximum number of results to list * `--unbounded` — Disable the result limit * `-l`, `--label ` — Narrow the listing to resources carrying all of the given labels, as `key=value` pairs (repeatable, or comma-separated) **Examples:** To see a human-friendly list of datasets in your workspace: kamu list To list datasets explicitly: kamu list datasets To list all resources across all types: kamu list '%' To list variable sets: kamu list variablesets To list variable sets whose name matches a pattern: kamu list 'vs/my-%' To list one resource by name or ID: kamu list 'vs/my-vars' kamu list 3d8d6d1c-6f7c-4c62-9f4e-7d8295e8fb69 To list several resource types at once: kamu list 'vs/app-%' 'ss/app-%' To list storages from a specific context: kamu list storages --context prod To see more details: kamu list -w To list only resources carrying a label: kamu list variablesets -l environment=production To require several labels at once: kamu list variablesets -l environment=production,tier=backend To get a machine-readable list of all resources: kamu list '%' -o csv To get a machine-readable list of datasets: kamu list -o csv ## `kamu log` Shows dataset metadata history **Usage:** `kamu log [OPTIONS] ` **Arguments:** * `` — Local dataset reference **Options:** * `-o`, `--output-format ` — Format of the output Possible values: `shell`, `yaml` * `-f`, `--filter ` — Types of events to include * `--limit ` — Maximum number of blocks to display Default value: `500` Metadata of a dataset contains historical record of everything that ever influenced how data currently looks like. This includes events such as: * Data ingestion / transformation * Change of query * Change of schema * Change of source URL or other ingestion steps in a root dataset Use this command to explore how dataset evolved over time. **Examples:** Show brief summaries of individual metadata blocks: kamu log org.example.data Show detailed content of all blocks: kamu log -o yaml org.example.data Using a filter to inspect blocks containing query changes of a derivative dataset: kamu log -o yaml --filter source org.example.data ## `kamu login` Authenticates with a remote ODF server interactively **Usage:** `kamu login [OPTIONS] [SERVER] [COMMAND]` **Subcommands:** * `oauth` — Performs non-interactive login to a remote Kamu server via OAuth provider token * `password` — Performs non-interactive login to a remote Kamu server via login and password **Arguments:** * `` — ODF server URL (defaults to kamu.dev) **Options:** * `--user` — Store access token in the user home folder rather than in the workspace * `--check` — Check whether existing authorization is still valid without triggering a login flow * `--access-token ` — Provide an existing access token * `--repo-name ` — Repository name which will be used to store in repositories list * `--skip-add-repo` — Don't automatically add a remote repository for this host ## `kamu login oauth` Performs non-interactive login to a remote Kamu server via OAuth provider token **Usage:** `kamu login oauth [SERVER]` **Arguments:** * `` — Name of the OAuth provider, i.e. 'github' * `` — OAuth provider access token * `` — ODF backend server URL (defaults to kamu.dev) ## `kamu login password` Performs non-interactive login to a remote Kamu server via login and password **Usage:** `kamu login password [SERVER]` **Arguments:** * `` — Specify user name * `` — Specify password * `` — ODF backend server URL (defaults to kamu.dev) ## `kamu logout` Logs out from a remote Kamu server **Usage:** `kamu logout [OPTIONS] [SERVER]` **Arguments:** * `` — ODF server URL (defaults to kamu.dev) **Options:** * `--user` — Drop access token stored in the user home folder rather than in the workspace * `-a`, `--all` — Log out of all servers ## `kamu new` Creates a new dataset manifest from a template **Usage:** `kamu new [OPTIONS] ` **Arguments:** * `` — Name of the new dataset **Options:** * `--root` — Create a root dataset * `--derivative` — Create a derivative dataset This command will create a dataset manifest from a template allowing you to customize the most relevant parts without having to remember the exact structure of the yaml file. **Examples:** Create `org.example.data.yaml` file from template in the current directory: kamu new org.example.data --root ## `kamu notebook` Starts the notebook server for exploring the data in the workspace **Usage:** `kamu notebook [OPTIONS]` **Options:** * `--address
` — Expose HTTP server on specific network interface * `--http-port ` — Expose HTTP server on specific port * `--engine ` — Engine type to use for the notebook Possible values: `datafusion`, `spark` * `-e`, `--env ` — Propagate or set an environment variable in the notebook (e.g. `-e VAR` or `-e VAR=foo`) This command will run the Jupyter server and the Spark engine connected together, letting you query data with SQL before pulling it into the notebook for final processing and visualization. For more information check out notebook examples at [https://github.com/kamu-data/kamu-cli](https://github.com/kamu-data/kamu-cli) ## `kamu pull` Pull new data into the datasets **Usage:** `kamu pull [OPTIONS] [DATASET]...` **Arguments:** * `` — Local or remote dataset reference(s) **Options:** * `-a`, `--all` — Pull all datasets in the workspace * `-r`, `--recursive` — Also pull all transitive dependencies of specified datasets * `--fetch-uncacheable` — Pull latest data from uncacheable data sources * `--as ` — Local name of a dataset to use when syncing from a repository * `--no-alias` — Don't automatically add a remote push alias for this destination * `--set-watermark