<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: jq</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/jq.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2025-05-09T18:55:24+00:00</updated><author><name>Simon Willison</name></author><entry><title>llm -f issue:... -m echo --no-log</title><link href="https://simonwillison.net/2025/May/9/private-issues/#atom-tag" rel="alternate"/><published>2025-05-09T18:55:24+00:00</published><updated>2025-05-09T18:55:24+00:00</updated><id>https://simonwillison.net/2025/May/9/private-issues/#atom-tag</id><summary type="html">
    &lt;p&gt;I had some notes in a GitHub issue thread in a private repository that I wanted to export as Markdown. I realized that I could get them using a combination of several recent projects.&lt;/p&gt;
&lt;p&gt;Here's what I ran:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export GITHUB_TOKEN="$(llm keys get github)"                                             
llm -f issue:https://github.com/simonw/todos/issues/170 \
  -m echo --no-log | jq .prompt -r &amp;gt; notes.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have a GitHub personal access token stored in my LLM keys, for use with Anthony Shaw's &lt;a href="https://github.com/tonybaloney/llm-github-models"&gt;llm-github-models&lt;/a&gt; plugin.&lt;/p&gt;
&lt;p&gt;My own &lt;a href="https://github.com/simonw/llm-fragments-github"&gt;llm-fragments-github&lt;/a&gt; plugin expects an optional &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; environment variable, so I set that first - here's &lt;a href="https://github.com/simonw/llm-fragments-github/issues/11"&gt;an issue&lt;/a&gt; to have it use the &lt;code&gt;github&lt;/code&gt; key instead.&lt;/p&gt;
&lt;p&gt;With that set, the &lt;code&gt;issue:&lt;/code&gt; fragment loader can take a URL to a private GitHub issue thread and load it via the API using the token, then concatenate the comments together as Markdown. Here's &lt;a href="https://github.com/simonw/llm-fragments-github/blob/87555488805ffc973b5fb45aa51eac83be2c839f/llm_fragments_github.py#L92-L126"&gt;the code for that&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Fragments are meant to be used as input to LLMs. I built a &lt;a href="https://github.com/simonw/llm-echo"&gt;llm-echo&lt;/a&gt; plugin recently which adds a fake LLM called "echo" which simply echos its input back out again.&lt;/p&gt;
&lt;p&gt;Adding &lt;code&gt;--no-log&lt;/code&gt; prevents that junk data from being stored in my &lt;a href="https://llm.datasette.io/en/stable/logging.html"&gt;LLM log database&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The output is JSON with a &lt;code&gt;"prompt"&lt;/code&gt; key for the original prompt. I use &lt;code&gt;jq .prompt&lt;/code&gt; to extract that out, then &lt;code&gt;-r&lt;/code&gt; to get it as raw text (not a &lt;code&gt;"JSON string"&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;... and I write the result to &lt;code&gt;notes.md&lt;/code&gt;.&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/github"&gt;github&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/plugins"&gt;plugins&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm"&gt;llm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthony-shaw"&gt;anthony-shaw&lt;/a&gt;&lt;/p&gt;



</summary><category term="github"/><category term="plugins"/><category term="projects"/><category term="jq"/><category term="llm"/><category term="anthony-shaw"/></entry><entry><title>Nomic Embed Code: A State-of-the-Art Code Retriever</title><link href="https://simonwillison.net/2025/Mar/27/nomic-embed-code/#atom-tag" rel="alternate"/><published>2025-03-27T20:03:56+00:00</published><updated>2025-03-27T20:03:56+00:00</updated><id>https://simonwillison.net/2025/Mar/27/nomic-embed-code/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.nomic.ai/blog/posts/introducing-state-of-the-art-nomic-embed-code"&gt;Nomic Embed Code: A State-of-the-Art Code Retriever&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Nomic have released a new embedding model that specializes in code, based on their CoRNStack "large-scale high-quality training dataset specifically curated for code retrieval".&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://huggingface.co/nomic-ai/nomic-embed-code"&gt;nomic-embed-code&lt;/a&gt; model is pretty large - 26.35GB - but the announcement also mentioned a much smaller model (released 5 months ago) called &lt;a href="https://huggingface.co/nomic-ai/CodeRankEmbed"&gt;CodeRankEmbed&lt;/a&gt; which is just 521.60MB.&lt;/p&gt;
&lt;p&gt;I missed that when it first came out, so I decided to give it a try using my &lt;a href="https://github.com/simonw/llm-sentence-transformers"&gt;llm-sentence-transformers&lt;/a&gt; plugin for &lt;a href="https://llm.datasette.io/"&gt;LLM&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;llm install llm-sentence-transformers
llm sentence-transformers register nomic-ai/CodeRankEmbed --trust-remote-code
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I can run the model like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;llm embed -m sentence-transformers/nomic-ai/CodeRankEmbed -c 'hello'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This outputs an array of 768 numbers, starting &lt;code&gt;[1.4794224500656128, -0.474479079246521, ...&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Where this gets fun is combining it with my &lt;a href="https://simonwillison.net/2023/Jun/18/symbex/"&gt;Symbex tool&lt;/a&gt; to create and then search embeddings for functions in a codebase.&lt;/p&gt;
&lt;p&gt;I created an index for my LLM codebase like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd llm
symbex '*' '*.*' --nl &amp;gt; code.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates a newline-separated JSON file of all of the functions (from &lt;code&gt;'*'&lt;/code&gt;) and methods (from &lt;code&gt;'*.*'&lt;/code&gt;) in the current directory - you can &lt;a href="https://gist.github.com/simonw/ac45c6638ea87942383e97c5cf69ae09"&gt;see that here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then I fed that into the &lt;a href="https://llm.datasette.io/en/stable/embeddings/cli.html#llm-embed-multi"&gt;llm embed-multi&lt;/a&gt; command like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;llm embed-multi \
  -d code.db \
  -m sentence-transformers/nomic-ai/CodeRankEmbed \
  code code.txt \
  --format nl \
  --store \
  --batch-size 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I found the &lt;code&gt;--batch-size&lt;/code&gt; was needed to prevent it from crashing with an error. &lt;/p&gt;
&lt;p&gt;The above command creates a collection called &lt;code&gt;code&lt;/code&gt; in a SQLite database called &lt;code&gt;code.db&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Having run this command I can search for functions that match a specific search term in that &lt;code&gt;code&lt;/code&gt; collection like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;llm similar code -d code.db \
  -c 'Represent this query for searching relevant code: install a plugin' | jq
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That &lt;code&gt;"Represent this query for searching relevant code: "&lt;/code&gt; prefix is required by the model. I pipe it through &lt;code&gt;jq&lt;/code&gt; to make it a little more readable, which gives me &lt;a href="https://gist.github.com/simonw/fdc1b48b20a99714200f5d3970b1dff4"&gt;these results&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;jq&lt;/code&gt; recipe makes for a better output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;llm similar code -d code.db \
  -c 'Represent this query for searching relevant code: install a plugin' | \
  jq -r '.id + "\n\n" + .content + "\n--------\n"'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output from that starts like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;llm/cli.py:1776

@cli.command(name="plugins")
@click.option("--all", help="Include built-in default plugins", is_flag=True)
def plugins_list(all):
    "List installed plugins"
    click.echo(json.dumps(get_plugins(all), indent=2))
--------

llm/cli.py:1791

@cli.command()
@click.argument("packages", nargs=-1, required=False)
@click.option(
    "-U", "--upgrade", is_flag=True, help="Upgrade packages to latest version"
)
...
def install(packages, upgrade, editable, force_reinstall, no_cache_dir):
    """Install packages from PyPI into the same environment as LLM"""
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Getting this output was quite inconvenient, so I've &lt;a href="https://github.com/simonw/llm/issues/853"&gt;opened an issue&lt;/a&gt;.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/embeddings"&gt;embeddings&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm"&gt;llm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nomic"&gt;nomic&lt;/a&gt;&lt;/p&gt;



</summary><category term="ai"/><category term="jq"/><category term="embeddings"/><category term="llm"/><category term="nomic"/></entry><entry><title>Run a prompt to generate and execute jq programs using llm-jq</title><link href="https://simonwillison.net/2024/Oct/27/llm-jq/#atom-tag" rel="alternate"/><published>2024-10-27T04:26:36+00:00</published><updated>2024-10-27T04:26:36+00:00</updated><id>https://simonwillison.net/2024/Oct/27/llm-jq/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;a href="https://github.com/simonw/llm-jq"&gt;llm-jq&lt;/a&gt; is a brand new plugin for &lt;a href="https://llm.datasette.io/"&gt;LLM&lt;/a&gt; which lets you pipe JSON directly into the &lt;code&gt;llm jq&lt;/code&gt; command along with a human-language description of how you'd like to manipulate that JSON and have a &lt;a href="https://jqlang.github.io/jq/"&gt;jq&lt;/a&gt; program generated and executed for you on the fly.&lt;/p&gt;

&lt;p&gt;Thomas Ptacek &lt;a href="https://twitter.com/tqbf/status/1850350668965359801"&gt;on Twitter&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The JQ CLI should just BE a ChatGPT client, so there's no pretense of actually understanding this syntax. Cut out the middleman, just look up what I'm trying to do, for me.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I &lt;a href="https://xkcd.com/356/"&gt;couldn't resist&lt;/a&gt; writing a plugin. Here's an example of &lt;code&gt;llm-jq&lt;/code&gt; in action:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre class="notranslate"&gt;llm install llm-jq
curl -s https://api.github.com/repos/simonw/datasette/issues &lt;span class="pl-k"&gt;|&lt;/span&gt; \
  llm jq &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;count by user login, top 3&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This outputs the following:&lt;/p&gt;
&lt;div class="highlight highlight-source-json"&gt;&lt;pre&gt;[
  {
    &lt;span class="pl-ent"&gt;"login"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;simonw&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"count"&lt;/span&gt;: &lt;span class="pl-c1"&gt;11&lt;/span&gt;
  },
  {
    &lt;span class="pl-ent"&gt;"login"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;king7532&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"count"&lt;/span&gt;: &lt;span class="pl-c1"&gt;5&lt;/span&gt;
  },
  {
    &lt;span class="pl-ent"&gt;"login"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;dependabot[bot]&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"count"&lt;/span&gt;: &lt;span class="pl-c1"&gt;2&lt;/span&gt;
  }
]
&lt;span style="color: blue"&gt;group_by(.user.login) | map({login: .[0].user.login, count: length}) | sort_by(-.count) | .[0:3]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The JSON result is sent to standard output, the &lt;code&gt;jq&lt;/code&gt; program it generated and executed is sent to standard error. Add the &lt;code&gt;-s/--silent&lt;/code&gt; option to tell it not to output the program, or the &lt;code&gt;-v/--verbose&lt;/code&gt; option for verbose output that shows the prompt it sent to the LLM as well.&lt;/p&gt;
&lt;p&gt;Under the hood it passes the first 1024 bytes of the JSON piped to it plus the program description "count by user login, top 3" to the default LLM model (usually &lt;code&gt;gpt-4o-mini&lt;/code&gt; unless you set another with e.g. &lt;code&gt;llm models default claude-3.5-sonnet&lt;/code&gt;) and system prompt. It then runs &lt;code&gt;jq&lt;/code&gt; in a subprocess and pipes in the full JSON that was passed to it.&lt;/p&gt;
&lt;p&gt;Here's the system prompt it uses, adapted from my &lt;a href="https://github.com/simonw/llm-cmd"&gt;llm-cmd plugin&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code class="notranslate"&gt;Based on the example JSON snippet and the desired query, write a jq program&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class="notranslate"&gt;Return only the jq program to be executed as a raw string, no string delimiters wrapping it, no yapping, no markdown, no fenced code blocks, what you return will be passed to subprocess.check_output('jq', [...]) directly. For example, if the user asks: extract the name of the first person You return only: .people[0].name&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I &lt;a href="https://gist.github.com/simonw/484d878877f53537f38e48a7a3845df2"&gt;used Claude&lt;/a&gt; to figure out how to pipe content from the parent process to the child and detect and return the correct exit code.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2024/llm-jq-card.jpg" alt="Example terminal screenshot of llm jq with the verbose option." style="max-width: 100%" /&gt;&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cli"&gt;cli&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/plugins"&gt;plugins&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/thomas-ptacek"&gt;thomas-ptacek&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/prompt-engineering"&gt;prompt-engineering&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm"&gt;llm&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="cli"/><category term="plugins"/><category term="projects"/><category term="thomas-ptacek"/><category term="ai"/><category term="jq"/><category term="prompt-engineering"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="llm"/></entry><entry><title>jqjq: jq implementation of jq</title><link href="https://simonwillison.net/2024/Jul/5/jqjq/#atom-tag" rel="alternate"/><published>2024-07-05T15:23:14+00:00</published><updated>2024-07-05T15:23:14+00:00</updated><id>https://simonwillison.net/2024/Jul/5/jqjq/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/wader/jqjq"&gt;jqjq: jq implementation of jq&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
2,854 lines of jq that implements a full, working version of jq itself. “A great way to show that jq is a very expressive, capable and neat language!”

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/eeqpis/jqjq_jq_implementation_jq"&gt;Lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;&lt;/p&gt;



</summary><category term="jq"/></entry><entry><title>DuckDB as the New jq</title><link href="https://simonwillison.net/2024/Mar/21/duckdb-as-the-new-jq/#atom-tag" rel="alternate"/><published>2024-03-21T20:36:20+00:00</published><updated>2024-03-21T20:36:20+00:00</updated><id>https://simonwillison.net/2024/Mar/21/duckdb-as-the-new-jq/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pgrs.net/2024/03/21/duckdb-as-the-new-jq/"&gt;DuckDB as the New jq&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The DuckDB CLI tool can query JSON files directly, making it a surprisingly effective replacement for jq. Paul Gross demonstrates the following query:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;select license-&amp;gt;&amp;gt;'key' as license, count(*) from 'repos.json' group by 1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;repos.json&lt;/code&gt; contains an array of &lt;code&gt;{"license": {"key": "apache-2.0"}..}&lt;/code&gt; objects. This example query shows counts for each of those licenses.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/x5immj/duckdb_as_new_jq"&gt;lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cli"&gt;cli&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sql"&gt;sql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/duckdb"&gt;duckdb&lt;/a&gt;&lt;/p&gt;



</summary><category term="cli"/><category term="sql"/><category term="jq"/><category term="duckdb"/></entry><entry><title>wddbfs – Mount a sqlite database as a filesystem</title><link href="https://simonwillison.net/2024/Feb/18/wddbfs/#atom-tag" rel="alternate"/><published>2024-02-18T03:31:25+00:00</published><updated>2024-02-18T03:31:25+00:00</updated><id>https://simonwillison.net/2024/Feb/18/wddbfs/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://adamobeng.com/wddbfs-mount-a-sqlite-database-as-a-filesystem/"&gt;wddbfs – Mount a sqlite database as a filesystem&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Ingenious hack from Adam Obeng. Install this Python tool and run it against a SQLite database:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wddbfs --anonymous --db-path path/to/content.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then tell the macOS Finder to connect to Go -&amp;gt; Connect to Server -&amp;gt; &lt;code&gt;http://127.0.0.1:8080/&lt;/code&gt; (connect as guest) - connecting via WebDAV.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/Volumes/127.0.0.1/content.db&lt;/code&gt; will now be a folder full of CSV, TSV, JSON and JSONL files - one of each format for every table.&lt;/p&gt;
&lt;p&gt;This means you can open data from SQLite directly in any application that supports that format, and you can even run CLI commands such as grep, ripgrep or jq directly against the data!&lt;/p&gt;
&lt;p&gt;Adam used WebDAV because "Despite how clunky it is, this seems to be the best way to implement a filesystem given that getting FUSE support is not straightforward". What a neat trick.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cli"&gt;cli&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/webdav"&gt;webdav&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;&lt;/p&gt;



</summary><category term="cli"/><category term="python"/><category term="sqlite"/><category term="webdav"/><category term="jq"/></entry><entry><title>jq 1.7</title><link href="https://simonwillison.net/2023/Oct/2/jq-17/#atom-tag" rel="alternate"/><published>2023-10-02T04:58:54+00:00</published><updated>2023-10-02T04:58:54+00:00</updated><id>https://simonwillison.net/2023/Oct/2/jq-17/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/jqlang/jq/releases/tag/jq-1.7"&gt;jq 1.7&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
First new release of jq in five years! The project has moved from a solo maintainer to a new team with a dedicated GitHub organization. A ton of new features in this release—I’m most excited about the new pick(.key1, .key2.nested) builtin for emitting a selected subset of the incoming objects, and the --raw-output0 option which outputs zero byte delimited lists, designed to be piped to “xargs -0”.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/json"&gt;json&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;&lt;/p&gt;



</summary><category term="json"/><category term="jq"/></entry><entry><title>Examples of floating point problems</title><link href="https://simonwillison.net/2023/Jan/13/examples-of-floating-point-problems/#atom-tag" rel="alternate"/><published>2023-01-13T15:41:29+00:00</published><updated>2023-01-13T15:41:29+00:00</updated><id>https://simonwillison.net/2023/Jan/13/examples-of-floating-point-problems/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://jvns.ca/blog/2023/01/13/examples-of-floating-point-problems/"&gt;Examples of floating point problems&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I learned so much practical stuff from this post by Julia Evans. There are no 32-bit floating point numbers between 262144.0 and 262144.03125, which breaks code that attempts to keep incrementing by 0.01. I knew about the JavaScript tweet ID problem (JavaScript can’t handle numbers like 1612850010110005250) but I didn’t realize it affected jq as well. Lots more great examples in here.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://mastodon.social/@Migueldeicaza/109682538770135667"&gt;@Migueldeicaza&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/julia-evans"&gt;julia-evans&lt;/a&gt;&lt;/p&gt;



</summary><category term="javascript"/><category term="jq"/><category term="julia-evans"/></entry><entry><title>jq language description</title><link href="https://simonwillison.net/2022/Apr/26/jq-language-description/#atom-tag" rel="alternate"/><published>2022-04-26T19:04:09+00:00</published><updated>2022-04-26T19:04:09+00:00</updated><id>https://simonwillison.net/2022/Apr/26/jq-language-description/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/stedolan/jq/wiki/jq-Language-Description"&gt;jq language description&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I love jq but I’ve always found it difficult to remember how to use it, and the manual hasn’t helped me as much as I would hope. It turns out the jq wiki on GitHub offers an alternative, more detailed description of the language which fits the way my brain works a lot better.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=31166956"&gt;psacawa on Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/documentation"&gt;documentation&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/programming-languages"&gt;programming-languages&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;&lt;/p&gt;



</summary><category term="documentation"/><category term="programming-languages"/><category term="jq"/></entry><entry><title>jc</title><link href="https://simonwillison.net/2021/Dec/5/jc/#atom-tag" rel="alternate"/><published>2021-12-05T23:05:11+00:00</published><updated>2021-12-05T23:05:11+00:00</updated><id>https://simonwillison.net/2021/Dec/5/jc/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/kellyjonbrazil/jc"&gt;jc&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
This is such a great idea: jc is a CLI tool which knows how to convert the output of dozens of different classic Unix utilities to JSON, so you can more easily process it programmatically, pipe it through jq and suchlike. “pipx install jc” to install, then “dig example.com | jc --dig” to try it out.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://blog.kellybrazil.com/2021/12/03/tips-on-adding-json-output-to-your-cli-app/"&gt;Tips on Adding JSON Output to Your CLI App&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cli"&gt;cli&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/json"&gt;json&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/unix"&gt;unix&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;&lt;/p&gt;



</summary><category term="cli"/><category term="json"/><category term="unix"/><category term="jq"/></entry><entry><title>datasette-jq</title><link href="https://simonwillison.net/2019/May/30/datasette-jq/#atom-tag" rel="alternate"/><published>2019-05-30T01:52:57+00:00</published><updated>2019-05-30T01:52:57+00:00</updated><id>https://simonwillison.net/2019/May/30/datasette-jq/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/simonw/datasette-jq"&gt;datasette-jq&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I released another tiny Datasette plugin: datasette-jq registers a single custom SQL function, jq(), which lets you execute the jq expression language against a JSON column (or literal value) to filter and transform the JSON data. The README includes a link to a live demo—it’s a neat way to play with the jq micro-language.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/simonw/status/1133912206859313152"&gt;@simonw&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;&lt;/p&gt;



</summary><category term="projects"/><category term="datasette"/><category term="jq"/></entry><entry><title>jq recipes</title><link href="https://simonwillison.net/2018/Aug/22/jq-recipes/#atom-tag" rel="alternate"/><published>2018-08-22T15:23:59+00:00</published><updated>2018-08-22T15:23:59+00:00</updated><id>https://simonwillison.net/2018/Aug/22/jq-recipes/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://remysharp.com/drafts/jq-recipes"&gt;jq recipes&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Remy Sharp’s handy collection of jq recipes, each one linking to an interactive demo on jqterm.com. I thought jq was just for extracting values from a JSON document—I hadn’t realized how powerful it was for modifying and extending those documents as well.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/json"&gt;json&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/remy-sharp"&gt;remy-sharp&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;&lt;/p&gt;



</summary><category term="json"/><category term="remy-sharp"/><category term="jq"/></entry><entry><title>gron</title><link href="https://simonwillison.net/2018/Apr/3/gron/#atom-tag" rel="alternate"/><published>2018-04-03T21:16:21+00:00</published><updated>2018-04-03T21:16:21+00:00</updated><id>https://simonwillison.net/2018/Apr/3/gron/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/tomnomnom/gron"&gt;gron&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Ingenious tool for working with JSON on the command line: run “gron URL/filepath” to transform a JSON document into a multi-line assignment structure designed to be easy to run grep against. Grep it, then pipe it back into “gron --ungron” to convert the filtered data back to JSON again. It solves a similar problem to jq—which is addressed in the README: “gron’s primary purpose is to make it easy to find the path to a value in a deeply nested JSON blob when you don’t already know the structure; much of jq’s power is unlocked only once you know that structure”.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/json"&gt;json&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jq"&gt;jq&lt;/a&gt;&lt;/p&gt;



</summary><category term="json"/><category term="jq"/></entry></feed>