Subscribe to this thread
Home - General / All posts - Manifold SQL Skill released for AI
Dimitri


7,650 post(s)
#25-Aug-26 14:37

Manifold today has released a Manifold SQL Skill package for use with AI models. It's a free download and is open sourced using the MIT license. The skill is very comprehensive, since it was built directly from the source code and thus covers all Manifold SQL functions and all parts of Manifold SQL syntax, and it was tested very systematically against every snippet of Manifold SQL that appears in the user manual.

If you're spending a few hundred a month for high end models you know they've gotten pretty good at writing Manifold SQL, at least for simple tasks. But even the very best models do much better on complex tasks with the skill installed. If you're working with free tier models or otherwise using simpler models there's no doubt that installing the skill is worth it. The user manual topic has some helpful comments on that.

From the What's New page:

When working with AI models a skill is a folder of instructions, scripts, and resources that a model loads dynamically to improve performance on specialized tasks. The Manifold SQL skill teaches an AI model to write, review, debug, and explain Manifold SQL, the query language of Manifold Release 9 and Manifold Viewer. The skill has been implemented for Anthropic's Claude model but the download also works with little or no modifications for many other popular models such as ChatGPT, Deepseek, Qwen, GLM, and others, either running through the web or installed and running locally.

For complete information see the Manifold SQL Skill user manual topic, including installation instructions for Claude and tips for use with other AI models. Download the skill's zip file from this link.

If you use an AI model to help write Manifold SQL, installing the skill is highly recommended. It helps both in free tier use of models and also paid models, including in agentic settings like Claude Code.

rk
685 post(s)
#25-Aug-26 15:10

I had to unpack and rezip it. Otherwise I got

Zip file contains path with invalid characters

from Claude. I didn't have to change any path.

Dimitri


7,650 post(s)
#25-Aug-26 17:01

The problem has been found and fixed.

There's a new build system being used now that assembles accessory files and it switched to using Windows Compress-Archive instead of 7z. However, Compress-Archive has a nasty habit of injecting backslashes even though the ZIP spec requires forward slashes. Windows unzippers don't care and accept both which is why typical unzipping in a Windows system doesn't show an issue. But Claude.ai enforces the ZIP spec rigorously and rejects the Compress-Archive zip. That's why your upack and rezip worked. Nothing about the archive itself is wrong. The system has gone back to using 7z, which is what the main build processes use for .zip files.

The corrected file has now replaced the old file on the web site. The new SHA256 hash is:

512df459c8f6571d46dbd4feeeede0ef7588d9c4c1bb74716f5b2b678102fe52

... and the size is 39,442 bytes. I've attached it to this response as well.

Thanks for finding this. To make sure this doesn't happen again there's been another layer of checks added to the automated build system for such files (there are hundreds, if not thousands, of checks). :-)

Attachments:
manifold-sql-skill-9.182.6.zip

artlembo


3,477 post(s)
#26-Aug-26 00:23

Using the uploaded Skill, ChatGPT failed on my first 5 examples. So, 0 for 5.

For one example, I wanted to perform relatively simple question about counting points inside areas. ChatGPT chose to use GeomOverlayContaining which was the correct decision. But, it made it overly complex, and did not seem to be aware of the s_ and o_ in the the GeomOverlayContaining. So, I had to make some corrections.

Here is what ChatGPT wrote:

codeSELECT    [FAO Soils].[mfd_id],

    [FAO Soils].[USDA], COUNT([mrds-trim].[name]) AS [PointCount] FROM    [FAO Soils] LEFT JOIN CALL GeomOverlayContaining([FAO Soils], [mrds-trim], 0) GROUP BY    [FAO Soils].[mfd_id],

    [FAO Soils].[USDA];

This is the correct query that I wrote:

codeSELECT

    [s_USDA],

    COUNT(*) AS [PointCount]

FROM

SELECT * FROM CALL GeomOverlayContaining([mrds-trim], [FAO Soils] , 0)

GROUP BY

    [s_USDA];

So a question is, should we tell ChatGPT about its error to teach it, or will the underlying LLM not actually learn in this case?

artlembo


3,477 post(s)
#26-Aug-26 00:38

I've been trying to teach ChatGPT to fix its original idea (it was trying to use a LEFT JOIN). I gave it my correct SQL to learn from. But, after numerous attempts it still couldn't get the query to run.

We left it at:

codeSELECT

    [Zones].[USDA],

    Coalesce([Counts].[PointCount], 0) AS [PointCount]

FROM

    (

        SELECT DISTINCT

            [USDA]

        FROM [FAO Soils]

    ) AS [Zones]

LEFT JOIN

    (

        SELECT

            [s_USDA],

            COUNT(*) AS [PointCount]

        FROM

            SELECT * FROM CALL GeomOverlayContaining([mrds-trim], [FAO Soils], 0)

        GROUP BY

            [s_USDA]

    ) AS [Counts]

ON

    [Zones].[USDA] = [Counts].[s_USDA];

and it acknowledged:

Your working SQL is evidence that my assumptions about Manifold SQL were wrong;

Dimitri


7,650 post(s)
#26-Aug-26 06:12

I could not resist trying Google's advice. Here is the custom GPT I created, using Google's step by step instructions. Note that since the "Instructions" box in the Configure tab is limited and is not enough to paste all of the SKILL.md you copy won't fit, I created a custom version of the SKILL.md file that had the first block omitted and told the GPT to use that.

I then launched that custom GPT. I gave it the following prompt:

The following query is supposed to be in Manifold SQL but it doesn't work. Please write a corrected version.

SELECT [FAO Soils].[mfd_id],

[FAO Soils].[USDA], COUNT([mrds-trim].[name]) AS [PointCount] FROM [FAO Soils] LEFT JOIN CALL GeomOverlayContaining([FAO Soils], [mrds-trim], 0) GROUP BY [FAO Soils].[mfd_id],

[FAO Soils].[USDA];

It responded with a very well-reasoned and helpful answer (the formatting is good in the original but lost in the copy/paste into this post):

Your query is mixing an ordinary `LEFT JOIN` with a Manifold spatial overlay table function. `GeomOverlayContained` is the appropriate direction here: FAO soil areas are the source objects, and the MRDS points are the overlay objects contained by those areas. The overlay result prefixes source fields with `s_` and overlay fields with `o_`. ([Manifold][1]) The Manifold function catalog confirms `GeomOverlayContained(<drawing>, <overlay>, <tolerance>)` as the table function signature.

If you want **every FAO soil polygon, including polygons containing zero MRDS points**, use:

```sql

-- $manifold$

SELECT

s.[mfd_id],

s.[USDA],

Coalesce(p.[PointCount], 0) AS [PointCount]

FROM

[FAO Soils] AS s

LEFT JOIN

(

SELECT

[s_mfd_id] AS [mfd_id],

Count([o_mfd_id]) AS [PointCount]

FROM CALL GeomOverlayContained(

[FAO Soils],

[mrds-trim],

0

)

GROUP BY

[s_mfd_id]

) AS p

ON s.[mfd_id] = p.[mfd_id];

```

This explicit outer join is important in current Manifold builds. Starting with 9.0.182.3, the `GeomOverlayXxx` functions changed from LEFT-JOIN-like behavior to **INNER-JOIN-like behavior**, so source objects having no spatial matches are no longer emitted by the overlay function itself. ([Manifold][2]) Manifold's normal `LEFT JOIN ... ON ...` syntax is shown in its current documentation. ([Manifold][3])

If you **do not care about soil polygons having zero points**, the query is much simpler:

```sql

-- $manifold$

SELECT

[s_mfd_id] AS [mfd_id],

[s_USDA] AS [USDA],

Count([o_mfd_id]) AS [PointCount]

FROM CALL GeomOverlayContained(

[FAO Soils],

[mrds-trim],

0

)

GROUP BY

[s_mfd_id],

[s_USDA];

```

There are three substantive corrections to your original:

1. **No `LEFT JOIN CALL GeomOverlay...` without an `ON` condition.** The overlay function itself produces the spatially matched table.

2. **Use `GeomOverlayContained`, not `GeomOverlayContaining`.** You want the MRDS points *contained by* the FAO soil polygons.

3. **Reference the overlay result fields as `[s_...]` and `[o_...]`**, for example `[s_mfd_id]`, `[s_USDA]`, and `[o_mfd_id]`, rather than `[FAO Soils].[mfd_id]` or `[mrds-trim].[name]`. Manifold's spatial overlay functions use those prefixes. ([Manifold][4])

I used `[o_mfd_id]` for the count instead of `[o_name]` because that counts **points**, even if an MRDS point happens to have a NULL `[name]`. The Manifold SQL guidance also specifically treats these `GeomOverlay*` functions as the engine's spatial-join family.

[1]: https://manifold.net/doc/mfd9/geom_sql_functions.htm?utm_source=chatgpt.com "Geom SQL Functions"

[2]: https://manifold.net/doc/mfd9/what_s_new_in_the_latest_build.htm?utm_source=chatgpt.com "What's New in the Latest Build"

[3]: https://manifold.net/doc/mfd9/join_example__join_into_a_query.htm?utm_source=chatgpt.com "Join Example: Join into a Query"

[4]: https://manifold.net/doc/radian/sql_example__geomoverlayadjacent_function.htm?utm_source=chatgpt.com "SQL Example: GeomOverlayAdjacent Function"

Hope that helps! As an experiment of results without the skill and with the skill this is very interesting: without the skill ChatGPT wrote a typically wrong query. But with the skill it shows profoundly greater understanding and does much better. By the way, I was using the free tier for ChatGPT so the instructions should work for anybody without requiring a paid account.

Attachments:
customGPT.jpg

Dimitri


7,650 post(s)
#26-Aug-26 04:30

Key questions:

1. Which ChatGPT model are you using? Open AI has a pretty wide range of models ranging from simple, which skill or no skill make the sorts of mistakes you indicated, to higher end models which tend to do much better.

2. Are you sure it is using the skill?

(There's actually a third question, which is why you don't just use Claude... :-) ...)

I haven't used the skill with ChatGPT so to figure out how to do that I asked the Google AI how. I gave Google this prompt:

I have a skill.md (and associated files) for a "skill" for Claude, the Anthropic model, that is fo

r Manifold SQL, which is a dialect of SQL that's slightly different from ANSI SQL. How do I use that skill package with the free, online tier of ChatGPT? I heard that ChatGPT can also use skills packages written to the Anthropic standard. Please give me step by step instructions.

Here is the answer that Google gave me:

You heard correctly: Agent Skills (the open standard behind Claude’s SKILL.md format) is cross-compatible with OpenAI’s platform. [1, 2, 3]

However, there is a major catch regarding the free tier of ChatGPT. The official, system-wide "Skills" menu tab (which lets you upload a .zip package that dynamically triggers via a forward-slash / command) is restricted to ChatGPT Business, Enterprise, and Education tiers. It is not natively built into the standard free UI. [3, 4]

Because your skill file is just standard Markdown plain text, you can bypass this limitation on the free tier using Custom GPTs or a per-session injection. Here are the step-by-step methods to get your Manifold SQL skill up and running for free. [2, 5, 6]

------------------------------

## Option 1: Create a "Custom GPT" (Recommended)

OpenAI allows free-tier users to create and use Custom GPTs. This behaves exactly like an installed skill, meaning your Manifold SQL rules will always be active inside that specific chatbot window. [5]

1. Open your SKILL.md file in any basic text editor (like Notepad or TextEdit).

2. Copy everything inside the file. (Note: You can omit the very top YAML block containing things like tags: or version:, but keep the name, description, and the body text.) [2]

3. Log into ChatGPT on your browser.

4. On the left sidebar, click Explore GPTs, then click + Create in the top right corner.

5. Click on the Configure tab at the top.

6. Give your GPT a name (e.g., Manifold SQL Assistant) and a brief description.

7. Paste the text you copied from SKILL.md directly into the Instructions box. [5]

8. Upload Associated Files: If your skill package has reference schemas, documentation folders, or query templates, scroll down to the Knowledge section, click Upload files, and attach them. [5]

9. Click Create / Save in the top right corner and set it to Only Me (or Anyone with a link).

Whenever you need to write Manifold SQL, just open this specific GPT from your sidebar. [7]

------------------------------

## Option 2: Run it via a Per-Session Upload

If you don't want to create a permanent Custom GPT and just want to use the skill on the fly in a single chat box, you can feed the package to ChatGPT manually. [8]

1. Package your SKILL.md file and its associated reference files into a standard ZIP folder.

2. Start a brand new chat on the free tier of ChatGPT.

3. Click the paperclip/attachment icon in the prompt box and upload your ZIP file.

4. Paste the following initialization prompt into the chat box alongside the file to force ChatGPT to read it like a Claude skill:

"I have attached a structured Agent Skill package intended for the SKILL.md standard. Please open the ZIP, read the instructions inside SKILL.md, ingest the associated reference files, and adopt this persona/workflow for the rest of this conversation. Do not improvise; strictly follow the dialect rules outlined for Manifold SQL. Confirm when you are ready."

[4, 9]

------------------------------

## ⚠️ A Crucial Tip for Dialect Swapping

Because Manifold SQL differs from ANSI SQL, standard models like GPT-4o have a strong habit of "forgetting" subtle dialect constraints halfway through a long chat and reverting back to standard ANSI syntax. [10]

To counter this, look at your SKILL.md instructions and ensure you have a highly explicit "Negative Constraints" or "What to Avoid" section. Explicit instructions like "NEVER use standard ANSI syntax for X, ALWAYS use Y" will keep the free tier from drifting into regular SQL patterns. [6]

If you encounter any formatting issues during the copy-paste process or if ChatGPT throws a syntax error, let me know what specific error you are seeing or which Manifold SQL rule it is breaking, and we can tighten up the instructions!

[1] [https://medium.com](https://medium.com/design-bootcamp/i-switched-from-chatgpt-to-claude-the-difference-nobody-is-talking-about-7be7c12a0b8e)

[2] [https://www.adventuresincre.com](https://www.adventuresincre.com/claude-skills-practical-guide/)

[3] [https://explainx.ai](https://explainx.ai/blog/how-to-use-skills-in-chatgpt-complete-guide-2026)

[4] [https://support.claude.com](https://support.claude.com/en/articles/12512180-use-skills-in-claude)

[5] [https://www.reddit.com](https://www.reddit.com/r/ChatGPT/comments/1ssr698/can_claudes_skills_custom_skillmd_instruction/)

[6] [https://promptguy.io](https://promptguy.io/how-to-use-claude-skills-on-chatgpt-and-gemini/)

[7] [https://www.youtube.com](https://www.youtube.com/watch?v=l7BziIpoqnw)

[8] [https://www.youtube.com](https://www.youtube.com/watch?v=mUZEoC5Gmkw&t=49)

[9] [https://www.youtube.com](https://www.youtube.com/shorts/q0N9II_wSRE)

[10] [https://www.truefoundry.com](https://www.truefoundry.com/blog/claude-skills)

artlembo


3,477 post(s)
#26-Aug-26 13:23

to briefly answer your question, yes, I am pretty sure it is using the Skill. Unless of course it is lying to me :-)

It's in my Library, and ChatGPT told me I don't have to ask, they will use it for that conversation. Subsequent conversations might have to be reminded.

As for why I am using ChatGPT, it's because it's what I've always used. The good news, of course, is that it uploaded without any issues whatsoever. But, once I hit Post Reply in this post, I'm going to set up a Claude account - ha, ha. I'll let you know how it goes.

artlembo


3,477 post(s)
#26-Aug-26 13:49

Just did it in Claude (5 minutes after I posted). I asked Claude:

In a Manifold GIS project, I have two layers:

[FAO Soils] (soil polygons) [mrds-trim] (mineral locations as points)

both layers use a field called [Geom] for the geometry.

[FAO Soils] has a field called [USDA] that gives the name soil type, and [mrds-trim] has a field called [name] that tells us what is mined at that location.

I want to find the total number of of mineral locations in each soil type, and what is mined. So, we need to make use of the GROUP BY command to quantify the unique [name] in each unique [USDA]. What is the SQL for that?

And, please utilize the skill that I uploaded.

Claude got it right on the first try with this query:

SELECT [Soils].[USDA], [Minerals].[name], Count(*) AS [LocationCount]

FROM [FAO Soils Table] AS [Soils], [mrds-trim Table] AS [Minerals]

WHERE GeomContains([Soils].[Geom], [Minerals].[Geom], 0)

GROUP BY [Soils].[USDA], [Minerals].[name]

ORDER BY [Soils].[USDA], [Minerals].[name];

Dimitri


7,650 post(s)
#26-Aug-26 15:47

That's great to hear. Do you know what Claude model you were using (I presume it was the free tier)? Anthropic has been on a real tear recently with Fable (and even Opus 5) producing incredibly good results even without help from a skill. But Fable is a costly model for everyday use.

Dimitri


7,650 post(s)
#26-Aug-26 15:45

Try working with the skill and ChatGPT using the approach I tested, standing up a custom GPT. I had never done that before and it took less than five minutes following the advice the Google AI gave me and it worked like a charm, dramatically different in terms of Manifold SQL awareness.

One of the things I don't like about ChatGPT is some of the hidden trickiness of it, where it might not be using the skill. Given that the free tier performed so well when I stood up the custom GPT using the skill it's hard to see how the results ChatGPT gave you came from a model that used the skill.

For example, the first query ChatGPT wrote for you has no awareness of the `s_`/`o_` prefixes at all — which is on the first page of the skill's overlay material. If it had really ingested the skill and was using it there's no way it could have missed that.

The other thing is that I followed Google's advice and inserted an explicit negative instruction (to the effect of never writing generic SQL but always writing Manifold SQL as set forth in the skill) as part of the Instructions in setting up the custom GPT. See the screenshot.

Anyway, I bet if you stood up a custom GPT using the skill you'd see a big change in ChatGPT compared to the issues your first two posts reported.

Either way, it will be a great help for the community, to hear more examples and case studies of using different AIs. It would be especially interesting to stand up a free model, like Qwen in a fully local setup with a midrange GPU and not a super expensive top of the line GPU to see how that goes.

By the way, in your other post it's always a good idea to include the table schema in your prompt. Easy to do with the new Copy button in the schema dialog.

artlembo


3,477 post(s)
#27-Aug-26 01:34

So I went ahead and loaded the skill in the free version Claude - it took about 5 minutes to ask Claude how to upload it and then actually do it. I then asked Claude the following question:

In a Manifold GIS project, I have two layers:

[FAO Soils] (soil polygons) [mrds-trim] (mineral locations as points)

both layers use a field called [Geom] for the geometry.

[FAO Soils] has a field called [USDA] that gives the name soil type, and [mrds-trim] has a field called [name] that tells us what is mined at that location.

I want to find the total number of of mineral locations in each soil type, and what is mined. So, we need to make use of the GROUP BY command to quantify the unique [name] in each unique [USDA]. What is the SQL for that?

it created the SQL correctly on the first try. So, I decided to get a little more theoretical, and asked it to generate hexagons with the following question:

In Manifold GIS version 9, I have a layer called [FAO Soils]. It has a geometry field called [Geom]. Can you create a tessellation of hexagons that have a vertex-to-vertex length of 1000 meters, and call the new drawing [hexagons]. The [FAO Soils] is in the Lambert Equal Area projection so it is in meters.

it worked the first time out of the box, and created 1.2M hexagons.

Attachments:
hexagons.jpg

danb

2,104 post(s)
#07-Oct-26 20:08

I am recently back to work after a couple of months on my travels and it is really great to see Manifold 9 being actively developed again. There are already some huge improvements and hopefully many more to come.

I also wanted to comment on how useful I have found the skill to be. I've simply attached it to a ChatGPT project in the free version and have found it a huge aid to productivity.

In common with all my use of AI so far, working with it is very much a collaboration rather than reliance on a magic answers box. As such, the more you put into the workflow the more useful material you will get out.

I have found that it doesn't always get the syntax 100% first time, which is fine, but it generally takes you most of the way there with the template which is already a great help. I am generally familiar enough these days with Manifold 9 to correct it and then it retains this knowledge.

Anyway, I just wanted to say that I think this is a great addition, and it is very generous of Manifold to release this as a freebie!

I also wonder is this the sort of thing that could also be produced for the object model scripting side of things? That would also be of enormous use to me at least.


Landsystems Ltd ... Know your land | www.landsystems.co.nz

dchall8
1,041 post(s)
#08-Oct-26 06:20

This is a new concept in Manifold. Are you considering making a tutorial on YouTube?

rk
685 post(s)
#09-Oct-26 14:26

Thing to note:

I asked Claude:

/manifold-sql

i have tables [... 3 CREATE TABLE clauses ...]. Write manifold 9 sql that finds where 1 AreaA wholly contains exactly 1 AreaB and exactly 1 PointC, but the point is not inside AreaB.

Claude at first gave basically correct SQL, but using GeomContains().

In Manifold the optimal way is to use GeomOverlayContainedPar() and I had to remind it to Claude.

artlembo


3,477 post(s)
#09-Oct-26 14:48

I wonder if that is something you can put in the skills.md file. To tell Claude to always attempt to use the GeomOverlayxxxPar() functions in place of the traditional ones.

Manifold User Community Use Agreement Copyright (C) 2007-2021 Manifold Software Limited. All rights reserved.