What I wanted to solve
VoiceGIS began as a voice layer for maps. The harder problem turned out to be execution: how do you turn an ambiguous request into something an application can inspect before it changes state? The current core resolves language against real layers and fields, builds typed operations, checks permissions, and records what ran.
What made it difficult
- A command must resolve against the application's actual layers, fields, aliases, and capabilities.
- An attribute filter cannot turn into an unchecked SQL string.
- A stale or tampered plan has to be rejected before the first side effect.
- A risky operation may need confirmation from the user.
- The host application keeps ownership of its data, maps, permissions, and transcription experience.
- Speech providers and map libraries remain optional integrations.
- Remote services must advertise the capabilities needed for a request; a page-bounded response cannot be reported as complete.
How it works
- 1
Text or speech input
Input can come from a text box, Web Speech, Whisper, a host speech hook, or another transcription source.
- 2
Catalog-grounded compiler
The compiler resolves a command against the layers, aliases, fields, units, and actions supplied by the host.
- 3
Typed plan
The output is a serializable plan with operations, predicate ASTs, risk, permissions, required capabilities, and confirmation requirements.
- 4
Policy and preflight
Preflight checks authorization, confirmation, the catalog version, the plan schema, and adapter capabilities.
- 5
Application adapter
The host can supply its own adapter or use the shipped GeoJSON and OGC API Features adapters, whose capabilities are checked before execution.
- 6
Execution receipt
The receipt records the status of each operation and can emit lifecycle events into the host's audit trail.
- 7
MCP server
A read-only-by-default MCP server exposes the same catalog-grounded compiler and guarded OGC execution path to an agent.
Choices I made
Separate compilation from side effects
I separated planning from execution so the application can inspect, clarify, block, or request confirmation before an adapter operation runs.
Use typed predicates instead of generated SQL
Attribute and spatial conditions become checked AST nodes. The host adapter decides how to translate them for its own environment; VoiceGIS never emits SQL.
Validate again at execution time
Compilation is not a permanent approval. I check policy and catalog grounding again immediately before the first side effect, which catches a plan that became stale or was changed after compilation.
Keep the host application in control
I use adapters because ArcGIS, Mapbox, OpenLayers, PostGIS, and local GeoJSON need different behaviour. VoiceGIS does not hide those choices behind generated code.
Keep the core headless
The compiler, policy layer, adapter contract, and executor have zero runtime dependencies. Speech and the legacy map integrations sit outside that core.
Resolve places from a host-owned gazetteer
The built-in place resolver uses a list the application controls. Unknown places return suggestions instead of making an uncontrolled geocoding request or inventing a destination.
How I tested it
- Before publishing, the release guard runs tests, lint, ESM and CommonJS builds, and declaration generation.
- Changed layer IDs, unknown predicate fields, missing capabilities, unknown schemas, and stale catalog versions are rejected before an adapter runs.
- Serializable plans carry versions, required capabilities, permissions, and the IDs of operations that need confirmation.
- A historical evaluation artifact keeps 538 reproducible cases for the earlier rule-based parser.
- The Playwright suite serves fixture responses and fails any unexpected outbound request, so the browser workflow can be tested without the network.
- An opt-in live integration check exercises the OGC adapter against a public conformant service.
Known failure modes
- Ambiguous language returns needs_input rather than inventing a target.
- A forbidden operation returns blocked.
- An adapter without a required capability fails during preflight.
- A changed catalog or tampered plan fails the execution-time check.
- A valid transcript can still fall outside the compiler's language grammar.
- An OGC service without filtering support fails capability preflight instead of receiving a query it cannot honour.
What works now
- The compiler handles navigation, layer visibility, filtering, spatial selection, counts, buffers, exports, history, and adapter switching.
- The defaults grant only view and query permissions. A host must opt into higher-risk capabilities.
- Every execution returns a status for each operation and can emit lifecycle events.
- A host can add domain language through resolvers without forking the compiler.
- The earlier parser passed 504 of 538 stored cases, or 93.7%, in its separate evaluation artifact.
- The published package ships ESM, CommonJS, and declarations with zero runtime dependencies.
- The same guarded pipeline can be used from an MCP client against an OGC API Features service.
What it doesn't do yet
- VoiceGIS Core is a controlled command compiler, not a general conversational model.
- The host must provide the catalog and implement the adapters.
- The package does not generate SQL, invent fields, or give itself permissions.
- The 93.7% figure measures the earlier parser corpus, not the current catalog-grounded compiler.
- It is also not microphone-to-action speech-recognition accuracy.
- The OGC adapter has been validated against one conformant service, and its options may change as more implementations are tested.
- The place resolver covers a bounded set of navigation phrasings and depends on a gazetteer supplied by the host.