{"id":13631950,"url":"https://github.com/adityaathalye/shite","last_synced_at":"2025-04-08T04:16:27.363Z","repository":{"id":39996206,"uuid":"467701042","full_name":"adityaathalye/shite","owner":"adityaathalye","description":"The little hot-reloadin' static site maker from shell.","archived":false,"fork":false,"pushed_at":"2024-09-10T07:04:37.000Z","size":52114,"stargazers_count":231,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-30T12:33:44.196Z","etag":null,"topics":["bash","bash-script","every-layout","functional-programming","markdown","org-mode","shell","shell-script","static-site","static-site-generator"],"latest_commit_sha":null,"homepage":"https://www.evalapply.org","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adityaathalye.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2022-03-08T22:51:32.000Z","updated_at":"2025-03-29T16:41:50.000Z","dependencies_parsed_at":"2022-09-09T13:40:53.555Z","dependency_job_id":"a989317d-6164-4559-a871-a4ae51819048","html_url":"https://github.com/adityaathalye/shite","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adityaathalye%2Fshite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adityaathalye%2Fshite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adityaathalye%2Fshite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adityaathalye%2Fshite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adityaathalye","download_url":"https://codeload.github.com/adityaathalye/shite/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247773720,"owners_count":20993639,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["bash","bash-script","every-layout","functional-programming","markdown","org-mode","shell","shell-script","static-site","static-site-generator"],"created_at":"2024-08-01T22:02:46.018Z","updated_at":"2025-04-08T04:16:27.329Z","avatar_url":"https://github.com/adityaathalye.png","language":"Shell","funding_links":[],"categories":["Shell"],"sub_categories":[],"readme":"[![justforfunnoreally.dev badge](https://img.shields.io/badge/justforfunnoreally-dev-9ff)](https://justforfunnoreally.dev)\n\nshite\n---\n\nThe little hot-reloadin' static site generator from shell. Assumes Bash 4.4+.\n\nWARNING: Here be yaks!\n\n`shite`'s job is to help me make my website: https://evalapply.org\nThus, `shite`'s scope, (mis)feature set, polish will always be production-grade,\nwhere production is \"works on my machine(s)\" :)\n\n![much write. such Bash. very hotreload. wow.](demo/shite-demo-02-hotreload-content-edits-5fps-1024px.gif \"much write. such Bash. very hotreload. wow.\")\n\n\u003c!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc --\u003e\n**Table of Contents**\n\n- [shite](#shite)\n- [Introduction](#introduction)\n    - [Dreams and desires](#dreams-and-desires)\n    - [Backstory](#backstory)\n- [Usage Demo](#usage-demo)\n    - [Hot-reloaded shite editing](#hot-reloaded-shite-editing)\n        - [hotreload begins](#hotreload-begins)\n        - [hotreload content edits](#hotreload-content-edits)\n        - [hotreload style edits](#hotreload-style-edits)\n        - [hotreload template edits](#hotreload-template-edits)\n        - [hot rebuild indices and feeds](#hot-rebuild-indices-and-feeds)\n    - [Full site builds](#full-site-builds)\n    - [Environment Variables and Debug flags](#environment-variables-and-debug-flags)\n- [Design and Internals](#design-and-internals)\n    - [File and URL naming scheme](#file-and-url-naming-scheme)\n    - [Code organisation](#code-organisation)\n    - [Calling the code](#calling-the-code)\n    - [Templating system](#templating-system)\n    - [Metadata and front matter system](#metadata-and-front-matter-system)\n        - [For orgmode content](#for-orgmode-content)\n        - [For markdown content](#for-markdown-content)\n        - [For html content](#for-html-content)\n    - [Bashful Hot Reloading Sans Javascript](#bashful-hot-reloading-sans-javascript)\n        - [The event system](#the-event-system)\n        - [Liveness criterion](#liveness-criterion)\n        - [Hot reload scenarios](#hot-reload-scenarios)\n        - [Hot reload behaviour](#hot-reload-behaviour)\n    - [Unrealised Ambitions](#unrealised-ambitions)\n        - [From any source dir to any publish dir from anywhere on my box](#from-any-source-dir-to-any-publish-dir-from-anywhere-on-my-box)\n        - [Hot deployment](#hot-deployment)\n        - [Hot deployment with local hot reload](#hot-deployment-with-local-hot-reload)\n        - [More creature comforts](#more-creature-comforts)\n- [Contributing](#contributing)\n- [License](#license)\n\n\u003c!-- markdown-toc end --\u003e\n\n# Introduction\n\nWell, `shite` aims to make websites.\n\n- It is a wee publishing system made of pipelined workflows, optionally driven\n  by streams of file events (for the hotreloadin' bits).\n\n- It will not surprise a Perl/PHP gentleperson hacker from the last century.\n\n- It exists because one whistles silly tunes and shaves yaks.\n\nThis is baaasically what it does (ref: the `shite_templating_publish_sources` function).\n\n``` shell\ncat \"${watch_dir}/sources/${url_slug}\" |\n    __shite_templating_compile_source_to_html ${file_type} |\n    __shite_templating_wrap_content_html ${content_type} |\n    __shite_templating_wrap_page_html |\n    ${html_formatter_fn} |\n    tee \"${watch_dir}/public/${slug}.html\"\n\n```\n\n- It publishes content from org-mode files.\n- And html, and markdown.\n- It hot-builds.\n- It hot-reloads (no Javascript).\n- It does neither if you disdain creature comforts.\n- It does not _demand_ any server process for local publishing.\n- It is quite small.\n  ```shell\n  # The complete \"business logic\" is 300-ish lines as of this comment,\n  # counted as all lines except comments and blank lines.\n  grep -E -v \"\\s?\\#|^$\" \\\n      ./bin/{events,metadata,templating,utils,hotreload}.sh |\n     wc -l\n  ```\n- It is Bash-ful.\n- I _like_ it.\n\nBefore you get too exshited, may I warn you that the MIT license means I don't\nhave to give a shite if this little shite maker fails to make your shite work.\n[Contributing](#contributing) is replete with more warnings.\n\nAnd last but not least, I hereby decree that all texsht herein be read in Sean\nConnery voish.\n\n## Dreams and desires\n\nIn my `shite` dreams, I desire...\n\n- Above all, to keep it (the \"business logic\") _small_. Small enough to cache,\n  debug, and refactor in my head.\n\n- To install and use without superuser permission.\n\n- To _extremely_ avoid toolchains and build dependencies. No gems / npms / venvs\n  / what-have-yous. Thus, Bash is the language, because Bash is everywhere. And\n  standard packages like `pandoc` or `tidy`, when one needs _specific_ advanced\n  functionality.\n\n- Dependency-free templating with plain-ol' HTML set in good ol' heredocs.\n\n- Simple metadata system, content namespacing, static asset organisation etc.\n\n- Web server optional (or any kind of server process for that matter). We aim\n  for static sites, after all, which work just fine with `file://` navigation.\n\n- To construct it from small, composable, purely functional, Unix-tool-like\n  parts, because I like that sort of stuff a lot.\n\n- To give myself a seamless REPL-like edit-save-build-preview workflow.\n  - Hot-build page processing (compile + build on save.)\n  - Javascript-free browser hot-reloading. It works. It's terrible. It's awesome!\n  - TODO: Potentially also extend the same mechanism to hot-deploy, on git push\n    to a private repo on my own VPS somewhere. Maybe.\n\n## Backstory\n\nI accidentally restarted blogging after a long haitus. Before I could get words\ninto the cloud, I muddled about with \"modern\" Static Site Generators. Because\nWordPress is so last century (or so I told myself). Then I got annoyed by the\nSSG Jamstack bespoke templating building etc. magic. Now I am on the dark\npath of making this. It is being blogged about at:\n[shite: static sites from shell: part 1/2](https://www.evalapply.org/posts/shite-the-static-sites-from-shell-part-1/)\n\n# Usage Demo\n\nI use shite mainly in \"hotreload\" mode, mainly to write posts (in orgmode) and\nlive preview them (in Firefox). Less mainly, to hot-preview modifications to\nstyles and/or page templates. Least mainly, after labouring on a post interminably,\nI use it in \"don't hotreload\" mode to do a full site rebuild.\n\nshite demo examples below.\n\n## Hot-reloaded shite editing\n\nBasically this means that if I create, update, delete any file under `sources`,\nit must automatically translate to HTML, be published locally to `public`, and\ncause an appropriate page navigation or reload action in the web browser, where\nmy site is open.\n\n### hotreload begins\n\n![invoke shite in hotreload mode](demo/shite-demo-01-hotreload-begins-5fps-1024px.gif \"invoke shite in hotreload mode\")\n\nCall the \"main\" script in a clean new terminal session or tmux pane.\n\n``` shell\n./shite.sh\n```\n\nIt helpfully opens the index file in Firefox, according to the defaults I've set\nin `shite_global_data` array in `./shite.sh`.\n\n### hotreload content edits\n\n![hotreload content edits](demo/shite-demo-02-hotreload-content-edits-5fps-1024px.gif \"hotreload content edits\")\n\nIn your Emacs or Vim, open some content file under `sources`. Edit, save, and\nwatch the content appear in the browser. (Yes specifying Emacs/Vim is goofy,\nbecause I trigger _hot_ actions based on inotify events. Apparently different\neditors do file updates differently. I use Emacs or Vim, so I watch for the\nevents they cause, so it works on my machine. :)).\n\nFrequently the browser remembers the scroll position, which is neat. Sometimes\nthe hotreload is, well, shite. So I just hit space and save the content file to\ntrigger hotreload again.\n\n### hotreload style edits\n\n![hotreload style edits](demo/shite-demo-03-hotreload-style-edits-5fps-1024px.gif \"hotreload style edits\")\n\nGo to some static asset, like a CSS stylesheet. Alter a thing, like background\ncolor value. Save and watch the color change in the browser.\n\n### hotreload template edits\n\n![hotreload template edits](demo/shite-demo-04-hotreload-template-updates-5fps-1024px.gif \"hotreload template edits\")\n\nTweak some template fragment in `templates.sh`---say, blog post template. Then\nswitch to some blog post content file and modify it to trigger page build with\nthe modified template (e.g. hit space and save).\n\n### hot rebuild indices and feeds\n\n![hot rebuild indices and feeds](demo/shite-demo-05-hotreload-rebuild-indices-feeds-5fps-1024px.gif \"hot rebuild indices and feeds\")\n\nThis is a hack. The root index.org page under sources is special. If I modify it,\nthen it means I want to rebuild posts lists for the index page, for tags, and\nalso rebuild related meta-files like the RSS feed, sitemap, robots.txt etc.\n\n## Full site builds\n\n![full site build](demo/shite-demo-06-dont-hotreload-full-site-rebuild-5fps-1024px.gif \"full site build\")\n\nIn a clean new terminal session call `shite.sh` with \"no\", and optionally\nwith the `base_url` of the deployment environment:\n\nRebuild full site for \"local\" file:/// navigation. Truly \"serverless\" :)\n``` shell\n./shite.sh \"no\"\n```\n\nRebuild full site for publication under my domain.\n``` shell\n./shite.sh \"no\" \"https://evalapply.org\"\n```\n\n## Environment Variables and Debug flags\n\nThese flags alter the behaviour of the system.\n\n- Setting `SHITE_BUILD` to \"hot\" will run the event system in \"monitor\" mode,\n  which in turn drives hotreload behaviour. Setting it to \"no\" will suppress\n  browser hotreload.\n- Setting `SHITE_DEBUG_TEMPLATES` to \"debug\" will cause templates to be sourced\n  first, before publishing any templated source content.\n\n# Design and Internals\n\n`shite` is quite Unixy inside. Or so I'd like to think.\n\nCode is functional programming-style Bash. Everything is a function. Most\nfunctions are pure functions---little Unix tools in themselves. Most logic\nis pipeline-oriented. This works surprisingly well, because\n[Shell ain't a bad place to FP](https://www.evalapply.org/posts/shell-aint-a-bad-place-to-fp-part-1-doug-mcilroys-pipeline/).\n\nI also wanted a live interactive REPL-like experience when writing with `shite`,\nbecause I like working in live/interactive runtimes like Clojure and Emacs.\n\nSo, `shite` has become this fully reactive event-driven system capable of hot\nbuild-and-reload-on-save.\n\n## File and URL naming scheme\n\nThere are three main directory namespaces:\n\n- `sources` housing the \"source\" content, such as blog posts written in orgmode,\n  as well as CSS, Javascript, and other static assets.\n- `public` target for the compiled / built artefacts\n- `bin` for the shite-building code\n\nThe URL naming scheme follows sub-directory structure under `sources`, and is\nreplicated as-is under the `pubilic` directory structure. Since this is a bog\nstandard URL namespacing scheme, it also, applies directly to published content.\nLike so:\n\n``` text\nfile:///absolute/path/to/shite/posts/slug/index.html\n\nhttp://localhost:8080/posts/slug/index.html\n\nhttps://your-domain-name.com/posts/slug/index.html\n```\n\n## Code organisation\n\nAll \"public\" functions are namespaced as `shite_the_func_name`. All \"private\"\nfunctions are namespaced as `__shite_the_func_name`.\n\nFunctions exist to:\n\n  - define common page fragments (meta, header, footer etc.)\n  - compose full pages from components, metadata, and body content\n  - assemble the site... build and publish sources into public targets\n  - detect and process event streams to drive various site building features\n    site builds, and browser hot reloading\n  - react to processed events and drive hot compile of pages, hot build of site,\n    and browser hot reload / navigation\n  - provide convenience utilities for manual builds, local development\n\n## Calling the code\n\nIn a clean new terminal session:\n\n  - CD to the root of this project\n  - Source the dev utility code into the environment. This will bring in all the\n    business logic, templates, as well as dev utility functions.\n    ```bash\n    source ./bin/utils_dev.sh\n    ```\n  - Hit `shitTABTAB` or `__shiTABTAB` at the command line for autocompletions.\n  - Enter `type -a func_name` to print the function's definition and read its API.\n  - Set `shite_global_data` and `shite_page_data` as needed.\n  - Call functions at the command line. Call them individually, and/or composed\n    with other functions to test / exercise parts of the system.\n\n## Templating system\n\nTemplates exist for page fragments (like header, footer, navigation), and for\nfull page definitions (like the default page template). These are written as\nplain HTML wrapped in heredocs. `./bin/templates.sh` provides these.\n\nTemplates are filled-in with variable data from different sources:\n  - Bash associative arrays: `shite_global_data` contains site-wide metadata,\n    and `shite_page_data` contains page-specific metadata. Some outside process\n    must pre-set these arrays prior to processing any page.\n  - stdin: to inject content into the templates that are wrappers for content.\n  - function calls: to expand fragments like HTML metadata, links etc.\n\nFor example, a full page may be constructed as follows:\n\n```shell\ncat ./sample/hello.md |\n    pandoc -f markdown -t html |\n    cat \u003c\u003cEOF\n    \u003c!DOCTYPE html\u003e\n    \u003chtml\u003e\n        \u003chead\u003e\n            $(shite_template_common_meta)\n            $(shite_template_common_links)\n            ${shite_page_data[canonical_url]}\n        \u003c/head\u003e\n        \u003cbody ${shite_page_data[page_id]}\u003e\n            $(shite_template_common_header)\n            \u003cmain\u003e\n              $(cat -)\n            \u003c/main\u003e\n            $(shite_template_common_footer)\n        \u003c/body\u003e\n    \u003c/html\u003e\nEOF\n```\n\n## Metadata and front matter system\n\n`shite`'s metadata system is defined as key-value pairs. Keys name the metadata\nitems, and would be associated with whatever value of that type. Examples below.\n\nAs noted earlier, run-time metadata is carried in the environment by the\nassociative arrays `shite_global_data` and `shite_page_data`. These maybe be\npopulated by direct construction, as well as updated from external sources.\n\nEach page may specify its own metadata in \"front matter\" at the top of the page.\nThis will be used in addition page metadata derived from other sources.\n\n`shite` expects us to write front matter using syntax that is compatible with\nthe given content type, as follows.\n\n### For orgmode content\n\nUse comment lines `# SHITE_META` to demarcate the org-style metadata that `shite`\nshould also parse as page-specific metadata.\n\n```org\n# SHITE_META\n#+title: This is a Title\n#+slug: this/is/a/slug\n#+date: Friday 26 August 2022 03:38:01 PM IST\n#+tags: foo bar baz quxx\n# SHITE_META\n#+more_org_metadata: but not processed as shite metadata\n#+still_more_org_metadata: and still not processed as shite metadata\n\n* this is a top level heading\n\nthis is some orgmode content\n\n#+TOC: headlines 1 local\n\n** this is a sub heading\n   - this is a point\n   - this is another point\n   - a third point\n```\n\n### For markdown content\n\nWrite Jekyll-style YAML front matter, boxed between `---` separators.\n\n``` markdown\n---\nTITLE: This is a Title\nslug: this/is/a/slug\nDATE: Friday 26 August 2022 03:38:01 PM IST\nTAGS: foo BAR baz QUXX\n---\n\n# this is a heading\n\nthis is some markdown content\n\n## this is a subheading\n  - this is a point\n  - this is another point\n  - a third point\n```\n\n### For html content\n\nWe can simply use standard `\u003cmeta\u003e` tags, that obey this convention:\n`\u003cmeta name=\"KEY\" content=\"value\"\u003e`.\n\n``` html\n\u003cmeta name=\"TITLE\" content=\"This is a Title\"\u003e\n\u003cmeta name=\"slug\" content=\"this/is/a/slug\"\u003e\n\u003cmeta name=\"DATE\" content=\"Friday 26 August 2022 03:38:01 PM IST\"\u003e\n\u003cmeta name=\"TAGS\" content=\"foo BAR baz QUXX\"\u003e\n\n\u003ch1\u003eThis is a heading\u003c/h1\u003e\n\u003cp\u003eThis is some text\u003c/p\u003e\n\u003ch2\u003eThis is a subheading\u003c/h2\u003e\n\u003cp\u003e\n  \u003cul\u003e\n    \u003cli\u003eThis is a point\u003c/li\u003e\n    \u003cli\u003eThis is another point.\u003c/li\u003e\n    \u003cli\u003eThis is a third point.\u003c/li\u003e\n  \u003c/ul\u003e\n\u003c/p\u003e\n```\n\n## Bashful Hot Reloading Sans Javascript\n\nHere be Yaks!\n\nBeing entirely spoiled by Clojure/Lisp/Spreadsheet style insta-gratifying live\ninteractive workflows, I want hot reload and hot navigate in shite-making too.\n\nBut there does not seem to exist a standalone live web development server / tool\nthat does not also want me to download half the known Internet as dependencies.\nAs I said before, a thing I *extremely* do *not* want to do.\n\nDuckSearch delivered Emacs impatient-mode, which is quite hot, but I don't want\nto hardwire this my Emacs. Luckily, it also delivered this exciting brainwave\nfeaturing 'inotify-tools' and 'xdotool':\n[github.com/traviscross/inotify-refresh](https://github.com/traviscross/inotify-refresh)\n\nHot copy!\n\nBecause what could be hotter than my computer slammin' that F5 key *for* me? As\nif it *knew* what I really wanted deep down in my heart.\n\n### The event system\n\nThe event subsystem is orthogonal to everything else, and composes with the rest\nof the system.\n\nThe design is bog standard streaming architecture, viz. watch for file system\nevents, then filter, deduplicate, analyse, and route them (tee) to different\nevent processors. Currently there are just two such processors; one to compile\nand publish the page or asset associated with the event, another to hot reload\nthe browser (or hot navigate) depending on the same event.\n\nBaaasically this:\n\n``` shell\n# detect file events\n__shite_detect_changes ${watch_dir} 'create,modify,close_write,moved_to,delete' |\n    __shite_events_gen_csv ${watch_dir} |\n    # hot-compile-and-publish content, HTML, static, etc.\n    tee \u003e(shite_templating_publish_sources \u003e /dev/null) |\n    # browser hot-reload\n    tee \u003e(__shite_hot_cmd_public_events ${window_id} ${base_url} |\n              __shite_hot_cmd_exec)\n```\n\nEvents are simply a stream of CSV records structured like this:\n\n``` shell\nunix_epoch_seconds,event_type,base_dir,sub_dir,url_slug,file_type,content_type`\n```\n\nWe use different parts of the event record to cause different kinds of actions.\n\n### Liveness criterion\n\nThe afore-linked inotify-refresh script tries to *periodically* refresh a set of\nbrowser windows. We, however, want to be *very* eager. Any edit action on our\ncontent files and/or static assets must insta-trigger hot reload/navigate actions\nin the browser tab that's displaying our shite.\n\n### Hot reload scenarios\n\nWe want to define distinct reload scenarios: Mutually exclusive, collectively\nexhaustive buckets into which we can map file events we want to monitor.\n\nIf we do this, then we can model updates as a sort of write-ahead-log, punching\nevents through an analysis pipeline, associate them with the exact-match scenario,\nand then finally cause the action. For example:\n\nRefresh current tab when\n- static asset create, modify, move, delete\n\nGo home when\n- current page deleted\n\nNavigate to content when\n- current page content modified\n- any content page moved or created or modified\n\n### Hot reload behaviour\n\nSince we are making the computer emulate our own keyboard actions, it can mess\nwith our personly actions. If we stick to writing our shite in our text editor,\nand let the computer do the hotreloady thing, we should remain non-annoyed.\n\n## Unrealised Ambitions\n\nThere are many Yaks in the world.\n\n### From any source dir to any publish dir from anywhere on my box\n\nFor truly pervasive multi-site publishing mojo:\n\n- `shite` should be available on my PATH\n- I should be able to configure any source / public pair per site\n- Everything else should \"just work\" as it does\n\nThis is a small yak. I'll probably yakshave it soon.\n\n### Hot deployment\nObviously one can use the CI jobs of popular git hosts to trigger `shite` builds.\nBut why use clunky current-century tech, when we have already advanced to the\nstate of the art of the late 1900s... fully streaming and fully reactive?\n\nSarcasam aside, I don't see why the same event system cannot be used to add\nhot-deploy support, on a remote machine I run.\n\nOn the remote box:\n\n- a web server serves the public pages of the site\n- a clone of the site `sources` is enshrined\n- the selfsame hotreload process is live against `sources`\n  (minus the browser-watching).\n- a git checkout auto-triggers on receiving a git push\n- which should cause hot-build against the modified sources (with some special\n  case to trigger full build if a template changes)\n\nOn my local box:\n\n- edit, preview locally with local hotreloadin'\n- git commit, push sources to remote\n- hit F5 on the appropriate public URL `https://mydomain.com/posts/hello/index.html`\n- the hot-build should have completed in the time it takes to get to F5\n\n### Hot deployment with local hot reload\n\nDo something over SSH to bring browser refresh back to local box, in case of hot\ndeploys to remote server.\n\n- maybe Shell \"Session Portability\"?\n  [video](https://www.youtube.com/watch?v=uqHjc7hlqd0\u0026t=2436s \"Video: Shell Session Portability over SSH\"),\n  [slides](http://talk.jpnc.info/bash_oscon_2014.pdf \"Slides: Shell Session Portability over SSH\").\n- maybe tap the browser hotreload commands and stream only those back to my box,\n  with a \"server-mode\" for hot-publish at the remote box and a \"client-mode\" for\n  hot-reload on my local box?\n- maybe I'll find out it all \"just work\" with Emacs/TRAMP?\n\n### More creature comforts\nMaybe some \"Dev-ing/Drafting\" time setup/Teardown scenario? Maybe a 'dev_server'\nfunction that we use to kick start a new shite writing session?\n\n- xdg-open a new tab in the default browser (say, firefox), and goto the home\n  page of the shite based on config.\n- xdotool 'set_window --name' to a UUID for the life of the session.\n- Close the tab when we kill the dev session.\n\n# Contributing\n\nIf you got all the way down here, and _still_ want to contribute...\n\nWhy?\n\nWhy in the name of all that is holy and good, would you want to? Is it not\nblindingly obvious that this is the work of a goofball? Haven't you heard that\nBash is Not Even A Real Programming Language? And isn't it face-slappingly\nobvious that your PRs will languish eternally, and your comments will fall into\na nameless void?\n\nYes, sending patches is a terrible idea.\n\n_But_ please email me your hopes and dreams about your shite maker! I read email\nat my firstname dot lastname at gmail.\n\nTogether we can whistle silly tunes, and co-yak-shave our respective yaks, in\nour own special ways.\n\nMay The Source be with us.\n\n# License\n\nThis work is dual-licensed under the MIT license and the CC By-SA 4.0 license.\n\n- The Bash source code for making shite is licensed under the MIT license.\n- My website's content which I've included in this project, for demo purposes,\n  commit is licensed under the Creative Commons Attribution-ShareAlike 4.0\n  International License (CC By-SA 4.0).\n\nSPDX-License-Identifier: mit OR cc-by-sa-4.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadityaathalye%2Fshite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadityaathalye%2Fshite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadityaathalye%2Fshite/lists"}