{"id":20310856,"url":"https://github.com/progrium/clon-spec","last_synced_at":"2025-07-18T09:38:25.198Z","repository":{"id":61830567,"uuid":"555514326","full_name":"progrium/clon-spec","owner":"progrium","description":"Command-Line Object Notation: Ergonomic JSON-compatible input syntax for CLI tools.","archived":false,"fork":false,"pushed_at":"2022-10-23T16:23:08.000Z","size":6,"stargazers_count":23,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-01-14T12:15:45.802Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/progrium.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-10-21T18:30:11.000Z","updated_at":"2024-08-30T10:21:20.000Z","dependencies_parsed_at":"2023-01-20T12:00:26.421Z","dependency_job_id":null,"html_url":"https://github.com/progrium/clon-spec","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/progrium%2Fclon-spec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/progrium%2Fclon-spec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/progrium%2Fclon-spec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/progrium%2Fclon-spec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/progrium","download_url":"https://codeload.github.com/progrium/clon-spec/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241809614,"owners_count":20023787,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T17:34:48.742Z","updated_at":"2025-03-04T08:15:08.530Z","avatar_url":"https://github.com/progrium.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Command-Line Object Notation\nErgonomic JSON-compatible input syntax for CLI tools.\n\nCLON is an argument syntax spec for defining JSON-like objects in a way that makes sense for the command-line that isn't just taking raw JSON or pointing to a file. This was shamelessly stolen from [HTTPie](https://httpie.io/docs/cli/json) with some modification.\n\nCLON is not meant to be a tool itself, but an argument syntax that you can use when building CLI tools that need to take arbitrary JSON-like data. An example tool would be a CLI client for an RPC system with a usage format like `rpctool call \u003cmethod\u003e \u003cargs...\u003e`. CLON makes for a reasonably human-friendly way to input the argument data. Note that internally the tool may not use this syntax to build JSON, but a compatible format like CBOR, or even just to build an in-memory structure.\n\n### Implementations\n\nBelow are some language specific libraries for easily accepting this syntax in your command-line tools:\n\n * [progrium/clon-go](https://github.com/progrium/clon-go)\n * your library here\n\n## Simple Example\nIn these examples, `clon` is an *imaginary tool* that takes CLON arguments and outputs the resulting structure as JSON.\n\n```shell\n$ clon name=John email=john@example.org\n```\n```json\n{\n    \"name\": \"John\",\n    \"email\": \"john@example.org\"\n}\n```\n\nIf the first argument is in key-value form (with `=` or `:=` operator), the arguments will be used to construct an object. If the first argument is simply a value, the arguments will be used to construct an array. \n\n```shell\n$ clon John john@example.org \"Text string\"\n```\n```json\n[\n  \"John\",\n  \"john@example.org\",\n  \"Text string\"\n]\n```\n\n## Non-string JSON fields\nNon-string JSON fields use the `:=` separator, which allows you to embed arbitrary JSON data into the resulting JSON object. Additionally, text and raw JSON files can also be embedded into fields using `=@` and `:=@`:\n\n```shell\n$ clon \\\n    name=John \\                        # String (default)\n    age:=29 \\                          # Raw JSON — Number\n    married:=false \\                   # Raw JSON — Boolean\n    hobbies:='[\"http\", \"pies\"]' \\      # Raw JSON — Array\n    favorite:='{\"tool\": \"HTTPie\"}' \\   # Raw JSON — Object\n    bookmarks:=@files/data.json \\      # Embed JSON file\n    description=@files/text.txt        # Embed text file\n```\n```json\n{\n    \"age\": 29,\n    \"hobbies\": [\n        \"http\",\n        \"pies\"\n    ],\n    \"description\": \"John is a nice guy who likes pies.\",\n    \"married\": false,\n    \"name\": \"John\",\n    \"favorite\": {\n        \"tool\": \"HTTPie\"\n    },\n    \"bookmarks\": {\n        \"HTTPie\": \"https://httpie.org\",\n    }\n}\n```\n\nWhen building a top level array, values can be prefixed with `:` to indicate a non-string or raw JSON value. This is a shorthand for the top level array syntax described later.\n\n```shell\n$ clon John :29 :false :'{\"tool\": \"HTTPie\"}'\n```\n```json\n[\n  \"John\",\n  29,\n  false,\n  {\n    \"tool\": \"HTTPie\"\n  }\n]\n```\n\n## Nested JSON\nYou still use the existing data field operators (`=`/`:=`) but instead of specifying a top-level field name (like `key=value`), you specify a path declaration telling where and how to put the given value inside an object:\n\n```shell\n$ clon \\\n    platform[name]=HTTPie \\\n    platform[about][mission]='Make APIs simple and intuitive' \\\n    platform[about][homepage]=httpie.io \\\n    platform[about][stars]:=54000 \\\n    platform[apps][]=Terminal \\\n    platform[apps][]=Desktop \\\n    platform[apps][]=Web \\\n    platform[apps][]=Mobile\n```\n```json\n{\n    \"platform\": {\n        \"name\": \"HTTPie\",\n        \"about\": {\n            \"mission\": \"Make APIs simple and intuitive\",\n            \"homepage\": \"httpie.io\",\n            \"stars\": 54000\n        },\n        \"apps\": [\n            \"Terminal\",\n            \"Desktop\",\n            \"Web\",\n            \"Mobile\"\n        ]\n    }\n}\n```\n\n### Basic Usage\n\nLet’s start with a simple example, and build a simple search query:\n\n```shell\n$ clon \\\n    category=tools \\\n    search[type]=id \\\n    search[id]:=1\n```\n```json\n{\n    \"category\": \"tools\",\n    \"search\": {\n        \"id\": 1,\n        \"type\": \"id\"\n    }\n}\n```\n\nIn the example above, the `search[type]` is an instruction for creating an object called `search`, and setting the `type` field of it to the given value (`\"id\"`).\n\nAlso note that, just as the regular syntax, you can use the `:=` operator to directly pass raw JSON values (e.g, numbers in the case above).\n\nBuilding arrays is also possible, through `[]` suffix (an append operation). This creates an array in the given path (if there is not one already), and append the given value to that array.\n\n```shell\n$ clon \\\n    category=tools \\\n    search[type]=keyword \\\n    search[keywords][]=APIs \\\n    search[keywords][]=CLI\n```\n```json\n{\n    \"category\": \"tools\",\n    \"search\": {\n        \"keywords\": [\n            \"APIs\",\n            \"CLI\"\n        ],\n        \"type\": \"keyword\"\n    }\n}\n```\n\nIf you want to explicitly specify the position of elements inside an array, you can simply pass the desired index as the path:\n\n```shell\n$ clon \\\n    category=tools \\\n    search[type]=keyword \\\n    search[keywords][1]=APIs \\\n    search[keywords][0]=CLI\n```\n```json\n{\n    \"category\": \"tools\",\n    \"search\": {\n        \"keywords\": [\n            \"CLIs\",\n            \"API\"\n        ],\n        \"type\": \"keyword\"\n    }\n}\n```\n\nIf there are any missing indexes, they will be nullified in order to create a concrete object:\n\n```shell\n$ clon \\\n    category=tools \\\n    search[type]=platforms \\\n    search[platforms][]=Terminal \\\n    search[platforms][1]=Desktop \\\n    search[platforms][3]=Mobile\n```\n```json\n{\n    \"category\": \"tools\",\n    \"search\": {\n        \"platforms\": [\n            \"Terminal\",\n            \"Desktop\",\n            null,\n            \"Mobile\"\n        ],\n        \"type\": \"platforms\"\n    }\n}\n```\n\nIt is also possible to embed raw JSON to a nested structure, for example:\n\n```shell\n$ clon \\\n  category=tools \\\n  search[type]=platforms \\\n  search[platforms]:='[\"Terminal\", \"Desktop\"]' \\\n  search[platforms][]=Web \\\n  search[platforms][]=Mobile\n```\n```json\n{\n    \"category\": \"tools\",\n    \"search\": {\n        \"platforms\": [\n            \"Terminal\",\n            \"Desktop\",\n            \"Web\",\n            \"Mobile\"\n        ],\n        \"type\": \"platforms\"\n    }\n}\n```\n\nAnd just to demonstrate all of these features together, let’s create a very deeply nested JSON object:\n\n```shell\n$ clon \\\n    shallow=value \\                                # Shallow key-value pair\n    object[key]=value \\                            # Nested key-value pair\n    array[]:=1 \\                                   # Array — first item\n    array[1]:=2 \\                                  # Array — second item\n    array[2]:=3 \\                                  # Array — append (third item)\n    very[nested][json][3][httpie][power][]=Amaze   # Nested object\n```\n\n### Advanced Usage\n\n#### Top level arrays\n\nTo build an array instead of a regular object, you can simply do that by omitting the starting key:\n\n```shell\n$ clon \\\n    []:=1 \\\n    []:=2 \\\n    []:=3\n```\n```json\n[\n    1,\n    2,\n    3\n]\n```\n\nAs mentioned before, there is a shorthand to make this scenario much easier. The first argument must not be a key-value, but key-values can be used in later arguments producing a single key object. You can also use the raw value prefix `:` to include JSON arrays or objects.\n\n```shell\n$ clon :1 :2 :3 valid:=true :'[4, 5, 6]'\n```\n```json\n[\n    1,\n    2,\n    3,\n    {\n        \"valid\": true\n    },\n    [\n        4,\n        5,\n        6\n    ]\n]\n```\n\nFor more complex top level elements, you can use the standard notation to apply nesting to the items by referencing their index:\n\n```shell\n$ clon \\\n    [0][type]=platform [0][name]=terminal \\\n    [1][type]=platform [1][name]=desktop\n```\n```json\n[\n    {\n        \"type\": \"platform\",\n        \"name\": \"terminal\"\n    },\n    {\n        \"type\": \"platform\",\n        \"name\": \"desktop\"\n    }\n]\n```\n\n#### Escaping behavior\nNested JSON syntax uses the same escaping rules as the terminal. There are 3 special characters, and 1 special token that you can escape.\n\nTo include a bracket as is, escape it with a backslash (`\\`):\n\n```shell\n$ clon \\\n  'foo\\[bar\\]:=1' \\\n  'baz[\\[]:=2' \\\n  'baz[\\]]:=3'\n```\n```json\n{\n    \"baz\": {\n        \"[\": 2,\n        \"]\": 3\n    },\n    \"foo[bar]\": 1\n}\n```\n\nIf use the literal backslash character (`\\`), escape it with another backslash:\n\n```shell\n$ clon \\\n  'backslash[\\\\]:=1'\n```\n```json\n{\n    \"backslash\": {\n        \"\\\\\": 1\n    }\n}\n```\n\nA regular integer in a path (e.g `[10]`) means an array index; but if you want it to be treated as a string, you can escape the whole number by using a backslash (`\\`) prefix.\n\n```shell\n$ clon \\\n  'object[\\1]=stringified' \\\n  'object[\\100]=same' \\\n  'array[1]=indexified'\n```\n```json\n{\n    \"array\": [\n        null,\n        \"indexified\"\n    ],\n    \"object\": {\n        \"1\": \"stringified\",\n        \"100\": \"same\"\n    }\n}\n```\n\n#### Guiding syntax errors\n\nIf you make a typo or forget to close a bracket, the errors SHOULD guide you to fix it. For example:\n\n```\n$ clon \\\n  'foo[bar]=OK' \\\n  'foo[baz][quux=FAIL'\nSyntax Error: Expecting ']'\nfoo[baz][quux\n             ^\n```\n\nYou can follow to given instruction (adding a `]`) and repair your expression.\n\n#### Type safety\n\nEach container path (e.g., `x[y][z]` in `x[y][z][1]`) has a certain type, which gets defined with the first usage and can’t be changed after that. If you try to do a key-based access to an array or an index-based access to an object, you should get an error out:\n\n```\n$ clon \\\n  'array[]:=1' \\\n  'array[]:=2' \\\n  'array[key]:=3'\nType Error: Can't perform 'key' based access on 'array' which has a type of 'array' but this operation requires a type of 'object'.\narray[key]\n     ^^^^^\n```\n\nType Safety does not apply to value overrides, for example:\n\n```shell\n$ clon \\\n  user[name]:=411     # Defined as an integer\n  user[name]=string   # Overridden with a string\n```\n```json\n{\n    \"user\": {\n        \"name\": \"string\"\n    }\n}\n```\n\n## Raw JSON\n\nFor very complex JSON structures, it may be more convenient to pass it as raw input, for example:\n\n```shell\n$ echo -n '{\"hello\": \"world\"}' | clon\n```\n\n```shell\n$ clon \u003c files/data.json\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprogrium%2Fclon-spec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprogrium%2Fclon-spec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprogrium%2Fclon-spec/lists"}