The Coq Se(xp)rialized Protocol
SerAPI is a new library and communication protocol for the Coq proof assistant. It is based on automatic serialization of Ocaml datatypes from/to S-expressions; we aim to make low-level interaction with Coq easier, putting particular emphasis on IDE/tool developers. However, we believe that everybody can have some fun playing with our tool!
The main design principles of SerAPI are:
- Don't Repeat Yourself: We build on top of Coq's plugin API, we have canonical commands (search, print).
- Be extremely robust: Any crash is a critical bug; we are liberal in what we accept, and strict in what we produce.
- Make life easy: We are flexible with abstractions in order to provide a user-oriented interface.
SerAPI is still a proof-of-concept. However, it already supports async processing, most of the functionality available in Coq's XML protocol plus a few extra things, and runs quite well in the browser. Typical load times are less than a second.
Feedback from Coq users and developers is very welcome, contact us by mail or in the issue tracker!
SerApi development is discussed in the jsCoq mailing list, you can subscribe at:
The list archives should be also available at the Gmane group:
you can post to the list using nntp.
We will provide a more detailed roadmap for developers soon, for now you can find some sparse information below.
Quick Overview and Documentation
SerAPI is meant to be a basis for developers to build Coq IDEs and plugins.
If you are a Coq user, you have two choices:
- Use jsCoq and run Coq in your browser. JsCoq is the predecessor of SerAPI and will be shortly fully based on it. Meanwhile, you can access the embedding technology from our sister project.
- elcoq, a first emacs IDE prototype using SerAPI by Clément Pit--Claudel. This is not yet functional but already very cool!
If you are a developer, you can use SerAPI in 3 different ways:
onmessage/postMessageworker API. Ready-to-use builds are typically found here, we provide an example REPL at:
From your shell/application as a REPL:
sertoptoplevel reads and writes commands (S-Expressions) from stdin/stdout, in a machine or human-friendly format. Asynchronous processing is supported, see
sertop.native --helpfor an overview of the main options.
Ctrl-Cwill interrupt a busy Coq process in the same way than the standard
We recommend using
rlwrapor our emacs mode for direct interaction.
As an Ocaml library. You can directly link against the low-level serialization library
serlib/, or against the higher-level SerAPI protocol in
The installation process for the last two options is similar to a Coq plugin, we hope to provide an OPAM package soon; for now, see the build instructions.
SerAPI's main building block is the
CoqObject data type, a sum type encapsulating most core Coq objects.
API WARNING: Object packing will change in the future, however adapting should be straightforward.
Interaction happens by means of commands, which can be optionally tagged in the form of
(tag cmd); otherwise, an automatic tag will be assigned.
For every command, SerAPI will always reply with
(Answer tag Ack) to indicate that the command was successfully parsed and delivered to Coq, or with a
SexpError if parsing failed.
There are four categories of commands:
): control commands are similar to a function call and instruct Coq to perform some action. Typical actions are to check a proof, set an option, modify a
load path, etc... Every command will produce zero or more different tagged answers, and a final answer
(Answer tag Completed), indicating that there won't be more output.
(Query ((opt value) ...) kind): API WARNING: The Query API format is experimental and will change soon.
Queries stream Coq objects of type
kind. This can range from options, goals and hypotheses, tactics, etc... The first argument is a list of options:
predsis a list of conjunctive filters,
limitspecifies how many values the query may return.
ppcontrols the output format:
PpSerfor full serialization, or
PpStrfor "pretty printing". For instance:
(tag (Query ((preds (Prefix "Debug")) (limit 10) (pp PpSexp)) Option))
will stream all Coq options that start with "Debug", limiting to the first 10 and printing the full internal Coq datatype:
(CoqOption (Default Goal Selector) ((opt_sync true) (opt_depr false) (opt_name "default goal selector") (opt_value (StringValue 1)))) ...
Options can be omitted, as in:
(tag (Query ((limit 10)) Option)), and currently supported queries can be seen here
(Print opts obj): The
(Parse num string): The
Parsecommand gives access to the Coq parsing engine. We currently support detecting the end of the first num sentences, returning the corresponding
CoqPositionobjects. If you want to parse a document use the
StmAddcontrol command instead.
Look at the interface file more the details. The Ocaml type definitions are often self-explanatory and are serialized in a predictable way.
The build system is work in progress. coq/coq#187 needs to be completed before we upload SerAPI to Opam.
sertop requires OPAM and Coq 8.6. We will also provide an experimental branch tracking trunk soon.
- The current supported ocaml version is 4.04.0
$ opam switch 4.04.0 && eval `opam config env`.
- Install the needed packages:
$ opam install ocamlfind ppx_import cmdliner core_kernel sexplib ppx_sexp_conv camlp5.
- Download and compile coq 8.6. We recommend:
$ ./configure -local && make -j $NJOBS.
SERAPI_COQ_HOMEenvironment variable which points to your Coq sources, e.g.
sertop.el and run
M-x eval-buffer followed by
M-x sertop to get a sertop REPL in Emacs, with highlighting and pretty-printing (useful for debugging).
You may want to configure the variable
sertop-coq-directory to point out the location of Coq's stdlib.
There is a brief technical report at https://hal-mines-paristech.archives-ouvertes.fr/hal-01384408
See also the CHANGELOG.md.
[started] Implement Locate -> "file name where the object is defined". To improve.
Redo Query API, make objects tagged with a GADT. Critical: we hope to have gained enough experience to introduce the object tag
Improve the handling of names and environments, see
instantiate, the issue of
Nametab.shortest_qualid_of_globalis a very sensible one for IDEs
Maybe we could add some options
Best? ... Or we could even serialize the naming structure and let the ide decide if we export the current open namespace.
Help with complex codepaths: Load Path parsing and completion code is probably one of the most complex part of company-coq
- Support regexps in queries.
- Would be easy to get a list of vernacs? Things like
Typeclasses eauto, etc.
- Add a cache to full document parsing..
- enable an open CoqObject tag for plugin use (see coq/coq#209 ) ?
- Checkstyle support.
- ppx to enumerate datatypes. Write the help command with this and also Clément suggestions about Vernac enumeration.
Coq SerAPI has three main components:
serapi: an extended version of the current IDE protocol.
serliba library providing automatic de/serialization of most Coq data structures using
ppx_conv_sexp. This should be eventually incorporated into Coq itself. Support for
ppx_deriving_yojsonis work in progress.
sertop_js, toplevels offering implementation of the protocol.
Building your own toplevels using
serapi is encouraged. Here, the current limit is the ML API itself.
Commit tag conventions [work in progress]:
- [misc] : Code refactoring, miscellanenous
- [serlib] : Serialization lib.
- [sertop] : Sexp Toplevel.
- [doc] : Documentation.
- [build] : Build system.
- [proto] : Core protocol.
- [control] : STM protocol.
- [query] : Query protocol.
- [parse] : Parsing protocol.
- [print] : Printing protocol.
We prefer signed commits.
Quick demo (not always up to date)
rlwrap or the emacs mode is highly recommended:
coq-serapi$ rlwrap ./sertop.byte --prelude ~/external/coq-git/ (0 (Print () (CoqConstr (App (Rel 0) ((Rel 0)))))) > (Answer 0 Ack) > (Answer 0(ObjList((CoqString"(_UNBOUND_REL_0 _UNBOUND_REL_0)")))) (1 (Control (StmQuery 2 "Print nat. "))) > (Answer 1 Ack) > (Feedback((id(State 2))(contents Processed)(route 0))) > (Feedback((id(State 0))(contents(Message ....)))) (2 (Print () (CoqRichpp (Element ....)))) > (Answer 2 Ack) > (Answer 2(ObjList((CoqString"Inductive nat : Set := O : nat | S : nat -> nat\n\nFor S: Argument scope is [nat_scope]")))) (3 (Control StmState)) > (Answer 3 Ack) > (Answer 3(StmInfo 2)) (4 (Control (StmAdd () "Goal forall n, n + 0 = n."))) > (Answer 4 Ack) > (Answer 4(StmInfo 4)) (5 (Control (StmObserve 4))) > (Answer 5 Ack) > (Feedback((id(State 4))(contents(ProcessingIn master))(route 0))) > ... (Query ((sid 4) (pp ((pp_format PpStr)))) Goals) > (Answer 6 Ack) > (Answer 6(ObjList((CoqString"forall n : nat, n + 0 = n")))) (Query ((sid 4) (pp ((pp_format PpSer)))) Goals) > (Answer 7 Ack) > (Answer 7(ObjList((CoqGoal()(CProdN((fname"")....)))))) (8 (Control (StmAdd () "now induction n."))) > (Answer 8 Ack) > (Answer 8(StmInfo 5)) (10 (Control (StmObserve 5))) > (Answer 10 Ack) > (Feedback((id(State 5))(contents Processed)(route 0))) > ... (Query ((sid 4)) Goals) > (Answer 11 Ack) > (Answer 11(ObjList()))