{"slug": "projectured-one-data-structure-many-editable-views-with-an-ai-assistant", "title": "ProjecturEd: One data structure, many editable views, with an AI assistant", "summary": "ProjecturEd, a Julia-based application for viewing and editing structured data through multiple editable projections, demonstrated a local AI assistant building an M/M/1/K queue study in a video where the assistant typed seven requests and determined a buffer capacity of 13 to keep blocking under 1% at 80% load. The assistant, a local qwen3.8:27b model run by Ollama on the same computer, wrote the OMNeT++ network and configuration, inserted closed-form formulas, ran the model at load 0.8 with a buffer sweep from 1 to 15, plotted queue length and drops, and checked the simulation against the formula. ProjecturEd stores data as a tree of typed Julia values with views computed as projections, and the OMNeT++ tool shown in the video is built on ProjecturEd but is not in the public repository.", "body_md": "One structure, many editable views — with an AI assistant.\n\nProjecturEd is an application to view and edit structured data, and it is made to be extended.\nYou define your own data structures as documents and their views as projections, and one\ndocument can combine them with other kinds of data. About twenty domains come with it,\nfrom JSON and Markdown to Julia code, math and charts. Most views take your edits: an edit in a\nview changes the data, not a text copy of it. You and an AI assistant work together on the same data\nand the same views to reach one goal. The assistant edits with the same operations as you. It is written in Julia, so it is also a user interface for your own programs.\n\nIn this video a person types seven requests, and the AI assistant builds a study of an M/M/1/K\nqueue: how large must the buffer be to keep the blocking under 1 % at 80 % load? The assistant is\na local model, qwen3.8:27b, that Ollama runs on the same computer. It writes the network and the\nconfiguration of an OMNeT++ model, and it puts the closed form into the study as formulas. It\nruns the model at load 0.8 and a sweep of the buffer capacity from 1 to 15. Then it plots the\nqueue length and the drops, checks the simulation against the formula, and finds the answer: a\ncapacity of 13.\n\nThe study on the left is a document, and each step of the assistant is an edit of it. The\nrequests come from a script. The model is not scripted, and its code and its answers are its\nown. The video plays at the speed of the session, and it waits a few seconds before each call\nof the model, so the code can be read. The tool for OMNeT++ in the video is built on\nProjecturEd, and it is not in the public repository.\n\nThe idea\n\nThe data is the source. A view is computed from it.\n\nA text editor stores your work as a string of characters, and the structure is implicit. ProjecturEd stores the structure: a tree of typed Julia values. What is on the screen is a projection of that data, one of many possible notations, computed from it.\n\nA projection is a pair of functions. The printer makes the view, and records which part of the view came from which part of the data. The reader uses that record to turn an edit in the view into an operation on the data. So a view can be a block of JSON, an outline, a table, a diagram or formatted prose, and each one takes edits. You can write a projection of your own, for your own data or for data that exists.\n\nA text editor\n\nA text editor\n\nThe data is a string. A parser recovers the structure each time, and there is one notation.\n\nProjecturEd\n\nProjecturEd\n\nThe data is a tree, a table or a graph. Each notation is a projection of it. One piece of data can have several views, and an edit in one shows in the others. Every view reads the data through reactive cells, so no view on the screen can show an old value.\n\nJulia forms that draw a picture\n\nIn the evaluator, each form is Julia. A form that returns a canvas draws it in a pane beside\nthe evaluator, and each later form adds a part: a ring, a dot that circles the ring, a sine and\na cosine trace, and the links from the dot. A part that moves reads the clock, so the picture\nmoves while you type.\n\nDefine the structure of your data as documents and its views as projections. Navigation, search, copy and paste, filtered and sorted views, files, every backend and the assistant work on it with little or no extra code.\n\nLook into a running Julia program\n\nAny Julia value gets a view with no code: a tree that opens one level at a time. You can design a better view later.\n\nDesign a tool window without a GUI toolkit\n\nWidgets, tables, cards, tabs and split panes make a complete window. The window of ProjecturEd itself is made this way.\n\nEdit files as structures\n\nThe domains that come with ProjecturEd open, change and save their files through their own parsers, among them JSON, YAML, XML, Markdown, SQL and Julia.\n\nShow results and model behaviour\n\nCharts are documents, so you can select a data point like any other part. A state machine produces Julia code that runs, and a process flowchart runs with breakpoints and a live trace.\n\nAsk for a change in plain words\n\nThe assistant searches the API, writes Julia and runs it in the editor. It works with a local model through Ollama, or with Claude.\n\nCompared\n\nBeside a fixed interface, and beside an assistant that edits text.\n\nOrdinary software\n\nOne fixed interface\n\nAn application has one way to show its data: a grid, a form, a page. To see the data another way, you copy it into another tool.\n\nProjecturEd\n\nThe interface is a projection\n\nThe views are projections of one model: a grid, an outline, a form, a diagram. You choose one or write a new one, and the data is not copied.\n\nToday's AI assistants\n\nAn assistant that edits text\n\nThe model writes characters, and a parser reads them back. A change that does not parse is found after the fact.\n\nProjecturEd\n\nAn assistant that edits data\n\nThe model changes the data with the same typed operations as your key presses: insert an element, replace a value, move the selection. The same tests cover both. The window is a document too, so the assistant controls the whole user interface: it can open a tab, split a pane, scroll a view or add a button to the toolbar.\n\nCapabilities\n\nWhat it does.\n\nThe assistant works on the same data as you. The other three multiply: kinds of data, yours\ntoo, chains of projections and backends combine in many ways, so one new part adds many new\ncombinations.\n\nMade to be extended\n\nYour data, your views\n\nThe domains that come with ProjecturEd are examples, not the limit. A domain of your own is a\npackage: its document types, the projections that make its views, its operations and its key\nbindings. No other domain depends on it, and it combines with the others where their structures\nallow: your document can hold a table or a formula, and another document can hold yours. The general features work on it with little or no\nextra code: navigation, search, the clipboard, filtered and sorted views, files, every backend\nand the assistant, which can find and call your functions.\n\nA language model reads the document and the API of the loaded packages, and changes the data with operations, not with line numbers. It runs with a local model through Ollama, or with Claude.\n\nOne document, many kinds of data\n\nA document of one domain can hold a document of another, your own domain too: a formula in a table cell, JSON inside prose. Navigation and editing cross the boundary, and any part is a document of its own.\n\nComposable projections\n\nProjections chain, nest, sort, filter and focus. A sorted or filtered view still takes edits, because each step maps an edit back through the step below it.\n\nA window, a terminal or a browser\n\nThe same views run in a native window, in a terminal and in a browser, and with no screen for tests. A view also goes to a vector PDF, a PNG or an MP4. It runs from source, or as a built binary that needs no Julia.\n\nMore capabilities\n\nAn edit keeps the data well formed\n\nAn edit is a typed change of the data, so the structure stays well formed. Text that is not well formed yet has a place of its own: a hole in the document holds it as text. In a SQL or a Julia document, Enter parses the text of a hole into the tree. Text that does not parse stays in the hole, and you go on editing it. The conversation does the same for JSON, XML and Julia.\n\nOnly what you look at is computed\n\nParts of a document that are not on the screen cost nothing, so a view can show a part of a very large document, or of a list with no end. See the video.\n\nWhat is computed stays until it changes\n\nEach field of the data is a reactive cell, and a value computed from cells stays until one of them changes. A change marks the values that depend on it as invalid, and only those are computed again, when a view reads them. So every view stays consistent with the data, and the work after an edit follows what the edit changed.\n\nPlayback & recording\n\nA list of gestures drives a session from a script. The result goes to a screenshot or to a recorded video. Every video on this page was recorded this way: a script gave the keys and the clicks, and the editor drew each frame.\n\nTests for every example\n\nThe test suite walks every example: the printer output, the reader, and the navigation to each position. A static guard checks the layering of each package.\n\nA selection is a path\n\nThe selection is a path into the data: a position between two characters, an XML attribute, a function argument, a table column, a whole chapter. It survives a filter, a sort and a change elsewhere in the document.\n\nPaste the same object, or a copy\n\nCtrl+N notes a part without a change of the document. A paste then puts the same object in a second place, so an edit in one place shows in both. Ctrl+Shift+V pastes a copy instead. So you can keep as many collections of your own as you like: a list that gathers the parts of a task from your documents, where an edit in the list is an edit of the part itself.\n\nEvery command, and whether it runs here\n\nCtrl+Shift+P opens a command palette. It lists the commands at the current selection and marks each command that can not run now. Type part of a name, and Enter runs the command. F1 shows the same list with the keys. Both lists come from the projections in use.\n\nAI integration\n\nThe assistant works on the same data as you.\n\nThe tools a model can call are a layer of the editor itself: it reads the data you are looking at, searches the API of the loaded packages, writes Julia and runs it, and changes the data with the same typed edits your key presses make. So Ctrl+Z takes back a change by the assistant like one of yours. It runs with a local model through Ollama or with Claude, and an external client gets the same tools over MCP.\n\nViews on demand\n\nThe assistant opens views\n\nThe assistant can open a tab, arrange the panes, and build a card, a table or a form to show a result. So a window is put together for the task at hand, by you or by the assistant, from the same parts.\n\nOne tool: running code\n\nThe main tool runs Julia code in the process of the editor, with the editor bound to a variable. There is no fixed list of commands. It is not a sandbox: it is a tool for your own machine.\n\nTools that read\n\nBeside the code tool, two tools read: one reads the documentation of a function, and one reads a guide or another resource. So the model reads how a function works before it calls it.\n\nSearch by words, pattern or meaning\n\nTwo tools search the API of the loaded packages and the guides. A search takes keywords, a regular expression, or a description in plain English. For a description, a meaning model turns each text into a vector, and the search ranks the entries by their meaning. So the model finds a function before it calls it.\n\nIt changes data and views\n\nThe assistant edits the data and the projections that show it: it can add a sorted or filtered view, swap a notation, or restructure a document.\n\nA reply can hold a table, a formula or code\n\nThe conversation is a document. A turn can hold a table, a formula, a diagram or code, made by the assistant or put there by you.\n\nAsk, then edit\n\nYou can ask for a change in plain words, and then edit the result by hand in the same view.\n\nVideos\n\nShort sessions, recorded by the editor itself.\n\nThe keys of each video come from a script and play at the speed of a person typing. The editor\ndraws each frame, and nothing is cut or sped up.\n\nThe assistant edits a file\n\nA person asks the assistant to add Frank, 30, from Paris to people.json. The\nassistant is a local model that Ollama runs on the same computer. It writes Julia and runs it\nin the window: it reads the file, makes the new record, and inserts it with an edit, as a key\npress does. The edit goes into the history of the file, so a click in the file and\nCtrl+Z take Frank back. The person then asks for a table of the people, sorted by\nname, beside the file. The assistant reads the file again, finds five people, and opens the\ntable in a new pane.\n\nThe pane at the bottom is the gesture log of the window: each key of the person, and each\noperation, also the one that the assistant made. The model is not scripted, and its answers are\nits own. The video waits a few seconds before each call of the model, so the code can be read\nbefore its result opens.\n\nJSON from nothing\n\nAn empty document becomes a JSON object, typed with the keyboard alone. A key makes a typed\nelement, not a character: { makes an object, Tab goes from a key to\nits value, \" makes a string and , adds the next entry. ↓\nleaves a nested object or array. The panel at the bottom right is the gesture log of the editor:\neach key, and the operation it made on the data.\n\nTo open the same editor from a Julia session with the ProjecturEd packages:\n\n```\njulia> using Projectured, ProjecturedExample, ProjecturedSdl\n\n# an empty JSON document, drawn as JSON → syntax → text → graphics\njulia> run_example(JsonNothing(selection = @reference), ChainingProjection(\n           RecursiveProjection(JsonToSyntax()),\n           RecursiveProjection(SyntaxToText()),\n           TextToGraphics(measure = measure_sdl_text)))\n```\n\nThe window opens with the empty document selected. Press { to start.\n\nThe whole JSON domain is two short files:\nJsonDocument.jl\nsays what a JSON document is and what each key does to it, and\nJsonToSyntax.jl\nsays how it looks. They hold about 120 and 140 lines.\n\nThe rotating vector, form by form\n\nThe evaluator runs Julia in the program. A canvas that a form returns draws as itself, and\nit gets a pane of its own beside the evaluator. Each later form adds one part to it: a ring,\na dot that circles the ring, a sine and a cosine trace, the links from the dot, and the axes.\nA part that moves takes a function where it moves, so it follows the clock, and the picture\nchanges in its pane while the forms are typed.\n\nA tool window from widgets\n\nThe evaluator builds a small tool from widgets. The first forms make a cell, a button that\ncounts its presses in the cell, and a column that holds the button. An Alt+click selects the\nbutton in its result row, Alt+Up selects the column around it, and a split and a paste give\nthe tool a pane of its own. Each later form adds widgets to the tool: a label that counts the\npresses, a slider and a label that reads it, a text field, and a table of the three values. A\nlabel or a table cell that takes a function follows what the function reads, so each widget\nchanges at once when the button is pressed or the slider is dragged.\n\nThe presses and the drags are mouse events from the same script as the keys, and the video\ndraws the pointer.\n\nThe window is a document too\n\nIn the evaluator, editor is the window of the program. The forms walk down its\nfields: the screen holds the windows, a window holds a shell, and the shell holds the menu bar,\nthe toolbar and the status bar. The toolbar that a form returns draws as itself in its result\nrow. It is the same object as the toolbar of the window. A press on the copy opens the gesture\nlog, and the log lists that press as its newest gesture. A form that adds a button changes the\ntoolbar and its copy at once.\n\nA search of the window finds the file explorer, and a double-click in its copy opens a JSON\nfile in a new tab. A drag puts the tab beside the evaluator, and a second search finds the\ndocument of the tab. An edit in the tab shows in the result row, an edit in the result row\nshows in the tab, and Ctrl+Z takes both back: the two views show one\ndocument.\n\nA form that ends with ; hides its value, as in the Julia REPL, so the form\nthat adds the button shows no result.\n\nOnly what you look at is computed\n\nA list can have no end. One form in the evaluator defines all the primes, with the classic\nlazy sieve of Eratosthenes, and a pane shows the list. The label above the list counts the\nlinks of the list that exist: the rows that the pane has shown, and one more at each edge.\nWhen the wheel scrolls down, the count grows. When it scrolls back, the count stays the same,\nbecause each link is computed once.\n\nA filter of the list, the primes that end in 7, is a lazy list too. While it scrolls, the\ncount of the primes grows with it, because the filter asks the sieve for a prime only when it\nneeds one. The primes around one trillion start in the middle. Each one is found by a test of\nthat number alone, so the list reaches up and down from one trillion, and it computes only the\nrows on the screen.\n\nOnly what changes is painted again\n\nThe window paints again only the parts of the screen that changed, and a red outline shows\nthem. When the pointer moves over the toolbar or over the navigator, only the button or the\nrow that it leaves and the one that it enters are painted again. When a folder opens or\ncloses, its chevron and the rows below it are painted again, and the rows above it are not.\nWhen the navigator scrolls, every row moves, so all of the navigator is painted again, but the\npage beside it is not. A move of the caret by a line or by a word paints its old and its new\nplace, and a typed key paints only its own paragraph, and the paragraph below it when it grows\nby a line.\n\nThe editor finds this without a comparison of pixels. Every value on the screen is a reactive\ncell, and an event writes only a few cells. Before each frame, the backend compares the tree of\ngraphics with the last paint, and finds each graphic that draws something else, that moved, or\nthat came into the view or left it. Each change adds its old and its new rectangle to a set,\nand the backend paints each rectangle under its own clip. A container does not read the size\nof its children, so a change in one part of the window does not move the other parts. In the\nvideo each outline stays for 0.6 seconds, so that a repaint of a single frame can be seen.\n\nTo see the same outline in the program, open a Markdown file with the two switches on:\n\n``` bash\n$ PROJECTURED_PARTIAL_RENDER=1 PROJECTURED_DEBUG_DIRTY=1 bin/projectured notes.md\n```\n\nTry it\n\nClone it, and run it.\n\nYou need Julia 1.11 or later. A native window also needs SDL2 and SDL_ttf. The packages are not in\nthe General registry, so clone the repository.\n\n```\ngit clone https://github.com/projectured/projectured-julia\ncd projectured-julia\nbin/projectured\n```\n\nThe window opens with a file navigator on the left, the open files in tabs in the middle, and the\nassistant on the right. To open files at once, name them on the command line:\nbin/projectured notes.md data.json. The first start compiles the code, which takes some\nminutes. Later starts are fast.\n\n```\nbin/projectured --help                   # every option\nbin/projectured --backend=web a.json     # in a browser, at http://127.0.0.1:8080\nbin/projectured --assistant=anthropic    # with Claude: set ANTHROPIC_API_KEY first\n```\n\nBy default the assistant uses a local model through Ollama:\nthe Ollama server must run on your computer, and the model must be pulled.\nbin/build_projectured compiles the application into a binary that runs without Julia.\nThe quick start of the README\nhas the details.\n\nYou can also start from the Julia REPL. There are more than a hundred examples, and\nrun_example opens one in a window. The\nexamples tour lists them.\n\n``` bash\n$ julia --project=environment/all\njulia> using Projectured, ProjecturedExample, ProjecturedSdl\njulia> run_example(\"json\")        # one example in a window\n```\n\nBuild with ProjecturEd\n\nExamples, with the code that makes them.\n\nFrom here on, the page is for a developer. Each example is a document or a projection drawn by\nthe editor, and the Julia code beside it is what makes it. The catalog below lists the domains and\nthe projections that you can combine. The guides\nAdding a new domain and\nA view of your own data\nshow how to add your own.\n\nA domain in four parts\n\nThis is the JSON domain of ProjecturEd, cut down to its parts, and a domain of your\nown has the same four. The whole domain is two files,\nJsonDocument.jl and\nJsonToSyntax.jl, and the\nguide for a new domain\nbuilds one from the start.\n\n1 The documents\n\nA document type is a Julia struct. @document makes each field a cell, so an edit writes\nthe cell and every view that reads it follows. A field with a default is optional.\n\n```\n@document struct JsonString <: JsonDocument\n    value::String\nend\n\n@document struct JsonArray <: JsonDocument\n    elements::CellVector = CellVector()\n    collapsed::Bool = false\nend\n```\n\n2 A projection\n\nA projection is a struct too. @projection declares its parameters, here the style of\nthe quotes and the style of the value.\n\n```\n@projection struct JsonStringToSyntaxLeaf\n    quote_style::ImmutableCell{StyleText} =\n        StyleText(font_ubuntu_monospace_regular_20, color_solarized_yellow)\n    value_style::ImmutableCell{StyleText} =\n        StyleText(font_ubuntu_monospace_regular_20, color_solarized_green)\nend\n```\n\n3 What the projection makes\n\nA template says what the projection makes from a document: here a syntax leaf with quotes around\nthe value. @projection_template makes the printer and the matching reader from it, and\nbound ties the text to the field value, so an edit of the text writes the\nstring back. A projection can also be plain Julia code. It has four entry points, and each one\nworks on one level: the printer makes the view, the reader turns an edit of the view into an\noperation on the data, and two maps move a place, such as the selection, from the data to the\nview and back. Each of the four hands every child to the projection of that child, so domains\nnest and projections chain.\n\n``` php\n@projection_template JsonStringToSyntaxLeaf JsonString (prj, doc) ->\n    SyntaxLeaf(bound(:value, String,\n                     make_hinted_text(() -> json_escape(doc.value);\n                                      empty_thunk = () -> isempty(doc.value),\n                                      placeholder = \"enter json string\",\n                                      style = prj.value_style));\n               open = TextString(\"\\\"\", prj.quote_style),\n               close = TextString(\"\\\"\", prj.quote_style))\n```\n\n4 The projections together\n\nOne projection picks the projection for each document type. A chain then takes the JSON to\nsyntax, the syntax to text, and the text to graphics. run_example opens a document\nwith a projection in a window.\n\n```\nfunction JsonToSyntax()\n    TypeDispatchingProjection(\n        JsonNull        => JsonNullToSyntaxLeaf(),\n        JsonBool        => JsonBoolToSyntaxLeaf(),\n        JsonNumber      => JsonNumberToSyntaxLeaf(),\n        JsonString      => JsonStringToSyntaxLeaf(),\n        JsonArray       => JsonArrayToSyntaxNode(),\n        JsonObject      => JsonObjectToSyntaxNode(),\n        JsonInsertion   => JsonInsertionToSyntaxLeaf(),\n        JsonNothing     => InsertionNothingToSyntaxLeaf(),\n        JsonObjectEntry => JsonObjectEntryToSyntaxNode(),\n        Vector{Cell}    => CopyingProjection())\nend\n\nprojection = ChainingProjection(\n    RecursiveProjection(JsonToSyntax()),\n    RecursiveProjection(SyntaxToText()),\n    TextToGraphics(measure = FontFileMeasure()))\n\ndocument = JsonObject(\n    \"name\" => JsonString(\"Alice\"),\n    \"tags\" => JsonArray(JsonString(\"admin\"), JsonString(\"editor\")))\n\nrun_example(document, projection)\n```\n\nA rotating vector\n\nEach coordinate is a cell that reads the clock of the editor, so the scene is drawn again every frame.\n\n```\n# each animated value is a cell that reads the editor's clock,\n# so the scene re-renders every frame\ndot = GraphicsCircle(\n    () -> cx + r*cos(angle(get_reactive_time(clock))),\n    () -> cy - r*sin(angle(get_reactive_time(clock))),\n    7, color_solarized_magenta)\n\nGraphicsCanvas([background, ring, sin_chart, cos_chart, dot]; w, h)\n```\n\nA table with formulas\n\nA cell can hold a formula that is computed again when you edit. A table domain and a math domain, composed.\n\n```\n# a table widget whose cells can be live math, not just values\nWidgetTable(Point2D(40, 40),\n    [PrimitiveString(\"A\"), PrimitiveString(\"B\"), PrimitiveString(\"C\")],\n    [PrimitiveString(\"1\"), PrimitiveString(\"2\"), PrimitiveString(\"3\")],\n    [[PrimitiveNumber(10), PrimitiveNumber(20), PrimitiveNumber(30)],\n     # formulas, re-evaluated as you edit:\n     [MathBinaryOperation(:+, MathVariable(\"A\"), MathVariable(\"B\")),\n      MathBinaryOperation(:*, PrimitiveNumber(2), MathVariable(\"B\")),\n      MathBinaryOperation(:-, MathVariable(\"C\"), PrimitiveNumber(5))]])\n```\n\nSort without touching the data\n\nA sorted view is one more projection in the chain. Remove it, and the original order is back: the data was not changed.\n\n```\n# a sorted view is just one more projection in the pipeline —\n# the underlying list is never reordered\nChainingProjection(\n    SortingProjection(by = x -> x.value),\n    # … then render the collection as text …\n)\n```\n\nAny object, as a form\n\nThe reflection projection shows a plain struct as a form with text fields and checkboxes, with no user interface code.\n\n```\n# reflected into a form: the String becomes a text field,\n# each Bool a checkbox — no interface code written\n@document struct SearchSettings\n    query::String\n    case_insensitive::Bool\n    whole_word::Bool\nend\n```\n\nA query tool from widgets and SQL\n\nWidgets and SQL in one document: the query and a button on the left, the result table on the right. A split pane, a card, a button, a table and an SQL statement, composed.\n\n```\n# a query tool from widgets + SQL — one document, both domains\nWidgetSplitPane(:horizontal, [\n    WidgetCard(title = \"Query\", content = CellVector([\n        SqlSelectStatement(\"persons\"),          # SELECT * FROM persons\n        WidgetButton(Point2D(0,0), Point2D(120,40), \"Execute\")])),\n    WidgetTitlePane(\"Results\",\n        WidgetTable([\"name\", \"role\"], [],\n            [[\"Ada\", \"Lead\"], [\"Bob\", \"Engineer\"], [\"Cleo\", \"Ops\"]]))])\n```\n\nA graph with automatic layout\n\nYou give the vertices and the edges; the layout engine places the nodes and routes the connections. Each node here is a document of another domain: a table, JSON, an XML element.\n\n```\n# nodes are whole documents — a table, some JSON, an XML element;\n# describe vertices and edges, the layout & routing are automatic\nv_table = GraphVertex(table)   # table :: WidgetTable\nv_json  = GraphVertex(json)    # json  :: JsonObject\nv_xml   = GraphVertex(xml)     # xml   :: XmlElement\n\nGraphGraph(\n    [v_table, v_json, v_xml],\n    [GraphEdge(v_table, v_json; directed=true, label=\"uses\"),\n     GraphEdge(v_json,  v_xml;  directed=true),\n     GraphEdge(v_table, v_xml;  directed=false)])\n```\n\nOne function, three domains\n\nA Julia function whose body is an XML table, and the rows are a Julia loop. One document nests Julia, XML and Julia again, and each level takes edits in place.\n\n```\n# Julia and XML document constructors, combined into one tree\n# (the editor renders it as the syntax shown alongside)\nJuliaFunction(JuliaIdentifier(\"report\"), [JuliaIdentifier(\"rows\")],\n  JuliaBlock([\n    XmlElement(\"table\", [XmlAttribute(\"class\", \"report\")], [\n      XmlElement(\"tr\", [XmlElement(\"th\", [XmlText(\"Region\")]),\n                        XmlElement(\"th\", [XmlText(\"Revenue\")])]),\n      JuliaFor([JuliaForIterator(JuliaIdentifier(\"row\"),\n                                 JuliaIdentifier(\"rows\"))],\n        JuliaBlock([\n          XmlElement(\"tr\", [\n            XmlElement(\"td\", [JuliaFieldAccess(JuliaIdentifier(\"row\"),\n                                               JuliaIdentifier(\"region\"))]),\n            XmlElement(\"td\", [JuliaFieldAccess(JuliaIdentifier(\"row\"),\n                                               JuliaIdentifier(\"revenue\"))])])]))])]))\n```\n\nCatalog\n\nDomains and projections.\n\nA document belongs to a domain, and a projection turns it into a notation. These come with ProjecturEd, and they are a start, not a limit: a domain of your own joins them as a package, and the general projections below work on it too.\n\nDomains\n\nJSONXMLYAMLSQLJulia code, as a syntax treeGeneric syntax shared by JSON, XML, SQL & codeMath and formulasMarkdown and reStructuredTextStyled textTablesGraphs with automatic layoutCharts and sequence chartsState machines and processesGraphicsIconsImagesStyles · fonts & colorsWidgetsLayouts, also by constraintsThe file systemVersion history and undoAI conversationPanes, tabs and toolsyour own · as a packageany object · reflected… and combinations of them\n\nTransform any view\n\nSorting a sequenceFiltering a sequenceSearching by a predicateReversing a sequenceFocusing to a smaller part\n\nCompose & operate\n\nChaining into pipelinesDispatching by where it isRecursion into partsClipboard\n\nEach projection builds on the ones below it, and reuses their layout and their readers. So a sorted, filtered or searched view still takes edits.\n\nStatus & lineage\n\nUnder development, and the successor of a Common Lisp editor.\n\nStatus: under development. Most features work, but ProjecturEd is not a\nfinished product. Some parts are incomplete, and names and interfaces can still change. The\nroadmap\nlists what works today and what comes next. Problem reports and questions are welcome as\nGitHub issues.\n\nNon-commercial use is free, and it includes changes to the code. Commercial use needs a\nlicence from the author.\n\nProjecturEd began as an editor written in Common Lisp, and its source is public. The Julia\nversion is a new implementation of the same idea, with more domains, more backends and an AI\nassistant.\n\nIt is more than a hundred thousand lines of Julia, written through AI-assisted development with an automatic test suite. None of them was typed by hand.", "url": "https://wpnews.pro/news/projectured-one-data-structure-many-editable-views-with-an-ai-assistant", "canonical_source": "https://projectured.org", "published_at": "2026-09-28 15:08:21+00:00", "updated_at": "2026-09-28 15:20:29.960838+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "artificial-intelligence"], "entities": ["ProjecturEd", "Julia", "Ollama", "qwen3.8:27b", "OMNeT++"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/projectured-one-data-structure-many-editable-views-with-an-ai-assistant", "markdown": "https://wpnews.pro/news/projectured-one-data-structure-many-editable-views-with-an-ai-assistant.md", "text": "https://wpnews.pro/news/projectured-one-data-structure-many-editable-views-with-an-ai-assistant.txt", "jsonld": "https://wpnews.pro/news/projectured-one-data-structure-many-editable-views-with-an-ai-assistant.jsonld"}}