{"id":42856790,"url":"https://github.com/brianium/ascolais","last_synced_at":"2026-01-30T12:25:11.845Z","repository":{"id":333962094,"uuid":"1139453891","full_name":"brianium/ascolais","owner":"brianium","description":"A mystical place that is just lousy with magicians","archived":false,"fork":false,"pushed_at":"2026-01-22T13:12:36.000Z","size":63,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-22T15:27:36.025Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brianium.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-22T01:25:39.000Z","updated_at":"2026-01-22T13:12:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/brianium/ascolais","commit_stats":null,"previous_names":["brianium/ascolais"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/brianium/ascolais","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brianium%2Fascolais","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brianium%2Fascolais/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brianium%2Fascolais/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brianium%2Fascolais/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brianium","download_url":"https://codeload.github.com/brianium/ascolais/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brianium%2Fascolais/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28912909,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T12:13:43.263Z","status":"ssl_error","status_checked_at":"2026-01-30T12:13:22.389Z","response_time":66,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-30T12:25:07.892Z","updated_at":"2026-01-30T12:25:11.838Z","avatar_url":"https://github.com/brianium.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ascolais\n\nA [deps-new](https://github.com/seancorfield/deps-new) template for scaffolding full-stack Clojure web applications powered by the **sandestin effect ecosystem**.\n\n## Usage\n\nGenerate a new project:\n\n```bash\n# Using a published tag\nclojure -Sdeps '{:deps {io.github.brianium/ascolais {:git/tag \"v0.5.0\" :git/sha \"018964a\"}}}' \\\n  -Tnew create :template brianium/ascolais :name myorg/myapp\n\n# From local checkout\nclojure -Sdeps '{:deps {io.github.brianium/ascolais {:local/root \".\"}}}' \\\n  -Tnew create :template brianium/ascolais :name myorg/myapp\n```\n\nThis generates a complete, ready-to-run application at `myorg-myapp/`.\n\n## What You Get\n\nGenerated projects include:\n\n- **Integrant system** with PostgreSQL, HikariCP connection pooling, and ragtime migrations\n- **Effect-driven architecture** using sandestin for schema-validated, discoverable effects\n- **Datastar frontend** with SSE-based reactivity via twk\n- **Connection management** with sfere for broadcasting to connected clients\n- **Declarative routing** with kaiin generating routes from effect metadata\n- **Component sandbox** with tsain for REPL-driven UI development\n- **Claude Code integration** with comprehensive CLAUDE.md, skills, and formatting hooks\n\n### Project Structure\n\n```\nmyorg-myapp/\n├── deps.edn                    # Dependencies\n├── docker-compose.yml          # PostgreSQL for development\n├── CLAUDE.md                   # Comprehensive ecosystem docs\n├── tsain.edn                   # Component sandbox config\n│\n├── src/clj/myorg/myapp/\n│   ├── core.clj                # Application entry point\n│   ├── config.clj              # Integrant system configuration\n│   ├── routes.clj              # Ring route handlers\n│   ├── fx/                     # Effect registries (one per domain)\n│   └── views/                  # Hiccup view functions\n│       ├── layout.clj          # Page layout with Datastar setup\n│       └── components.clj      # Reusable UI components\n│\n├── dev/src/clj/\n│   ├── user.clj                # REPL initialization\n│   ├── dev.clj                 # Dev namespace (start/stop/reload)\n│   └── dev/config.clj          # Dev-specific Integrant config\n│\n├── resources/\n│   ├── migrations/             # SQL migration files\n│   └── public/styles.css       # Application styles\n│\n├── dev/resources/\n│   └── components.edn          # Tsain component library\n│\n└── .claude/\n    ├── settings.json           # Paren repair hooks\n    └── skills/                 # clojure-eval, tsain\n```\n\n## Technology Stack\n\nThe template brings together a cohesive set of libraries for building server-driven reactive applications:\n\n| Library | Purpose |\n|---------|---------|\n| [sandestin](https://github.com/brianium/sandestin) | Effect dispatch with schema-driven discoverability |\n| [twk](https://github.com/brianium/twk) | Datastar SSE integration for reactive frontends |\n| [sfere](https://github.com/brianium/sfere) | Connection management and pattern-based broadcasting |\n| [kaiin](https://github.com/brianium/kaiin) | Declarative HTTP routing from registry metadata |\n| [manse](https://github.com/brianium/manse) | Database effects with next.jdbc |\n| [tsain](https://github.com/brianium/tsain) | REPL-driven component development sandbox |\n\n### Supporting Libraries\n\n- **http-kit** - HTTP server\n- **reitit** - HTTP routing\n- **integrant** - Component lifecycle management\n- **malli** - Schema validation\n- **chassis** - Hiccup DSL with component aliases\n- **portal** - Data inspection (dev)\n- **clj-reload** - Namespace reloading (dev)\n- **ragtime** - Database migrations (dev)\n\n## Architecture\n\nGenerated projects follow an effect-driven architecture where all business logic flows through sandestin dispatch:\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                         HTTP Request                            │\n└──────────────────────────────┬──────────────────────────────────┘\n                               │\n                               ▼\n┌─────────────────────────────────────────────────────────────────┐\n│                    twk/with-datastar middleware                 │\n│  - Parses Datastar signals from headers                         │\n│  - Dispatches effects via sandestin                             │\n│  - Returns SSE responses                                        │\n└──────────────────────────────┬──────────────────────────────────┘\n                               │\n                               ▼\n┌─────────────────────────────────────────────────────────────────┐\n│                      sandestin dispatch                         │\n│  - Interpolates placeholders from request context               │\n│  - Expands actions → effect vectors                             │\n│  - Executes effects with interceptors                           │\n└──────────────────────────────┬──────────────────────────────────┘\n                               │\n            ┌──────────────────┼──────────────────┐\n            ▼                  ▼                  ▼\n    ┌──────────────┐   ┌──────────────┐   ┌──────────────┐\n    │  twk effects │   │ sfere effects│   │  app effects │\n    │ patch-elements│   │ broadcast    │   │  manse/db    │\n    │ patch-signals │   │              │   │  custom...   │\n    └──────────────┘   └──────────────┘   └──────────────┘\n```\n\n### Key Concepts\n\n**Effects** are side-effecting operations with schemas and descriptions:\n\n```clojure\n{::s/effects\n {:app/save-user\n  {::s/description \"Save user to database\"\n   ::s/schema [:tuple [:= :app/save-user] :map]\n   ::s/handler (fn [ctx system user]\n                 (db/save! (:db system) user))}}}\n```\n\n**Actions** are pure functions returning effect vectors:\n\n```clojure\n{::s/actions\n {:app/update-profile\n  {::s/description \"Update profile and notify\"\n   ::s/handler (fn [state changes]\n                 [[:app/save-user changes]\n                  [::twk/patch-elements [:div#status \"Saved!\"]]])}}}\n```\n\n**Kaiin metadata** on actions generates HTTP routes automatically:\n\n```clojure\n{::kaiin/path \"/api/users/:id\"\n ::kaiin/method :post\n ::kaiin/signals [:map [:name :string]]\n ::kaiin/dispatch [:app/update-profile [::kaiin/signal :name]]}\n```\n\n## Development Workflow\n\nAfter generating a project:\n\n```bash\ncd myorg-myapp\n\n# Start PostgreSQL\ndocker compose up -d\n\n# Start REPL\nclj -M:dev\n```\n\nIn the REPL:\n\n```clojure\n(dev)           ; Load dev namespace\n(start)         ; Start server at localhost:3000\n(reload)        ; Reload changed namespaces\n(restart)       ; Full stop + reload + start\n\n;; Discovery API\n(describe (dispatch))              ; List all effects\n(sample (dispatch) ::twk/patch-elements)  ; Generate examples\n(grep (dispatch) \"user\")           ; Search registry\n\n;; Database\n(migrate!)      ; Apply pending migrations\n(rollback!)     ; Undo last migration\n```\n\n### Component Development\n\nThe tsain sandbox at `localhost:3000/sandbox` provides a browser-based preview for iterating on UI components:\n\n```clojure\n;; Preview hiccup in browser\n(dispatch [[::tsain/preview [:h1 \"Hello World\"]]])\n\n;; Commit to component library\n(dispatch [[::tsain/commit :my-card {:description \"Card component\"}]])\n```\n\nCSS hot-reloads automatically when editing `resources/public/styles.css`.\n\n## Claude Code Integration\n\nGenerated projects are optimized for Claude-assisted development:\n\n- **CLAUDE.md** - Comprehensive documentation covering the entire effect ecosystem, patterns, and conventions\n- **Paren repair hooks** - Automatic Clojure formatting on file edits\n- **clojure-eval skill** - REPL evaluation via nREPL\n- **tsain skill** - REPL-driven component development with live preview, CSS styling, and library commits\n\n## Background\n\nThis template emerged from the [tsain](https://github.com/brianium/tsain) project's development, which needed a way to scaffold new applications using the sandestin ecosystem. The name \"ascolais\" comes from Jack Vance's *The Dying Earth* series, following the naming convention of sibling libraries.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrianium%2Fascolais","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrianium%2Fascolais","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrianium%2Fascolais/lists"}