Show HN: A Markdown-based alternative to package.json scripts and makefiles

github.com

80 points by timz 3 days ago

`x.md` allows you to organise your cli scripts in one or several markdown files, by mix and matching different scripting languages for various commands, such as zsh/bash/sh, python or javascript.

Handy for replacing one-line-based `package.json` scripts or `Makefile`s.

One can also write documentation and explanations to various commands in same `x.md` markdown file. ZSH autocompletions are also working, suggesting you the most relevant available commands from your `x.md` files.

Most editors highlight correctly most languages in the markdown code blocks, even when you use several scripting languages.

Provided the following example (x.md file in the root of your project), one can run in a terminal:

    $ x weather-tomorrow
or

    # x generate-password



    --- An example of x.md file ---

    # hello

    Prints "Hello" to `stdout` using Zsh.

    ```zsh
    echo "Hello"
    ```

    # world

    Just prints "World" to `stdout` using JavaScript.

    ```js
    console.log("World");
    ```

    # weather-tomorrow

    Prints the weather for tomorrow to `stdout` using Zsh.

    ```zsh
    curl wttr.in/tomorrow
    ```

    # generate-password

    Prints a random password to `stdout` using Python.

    ```python
    import random
    import string

    length = 16

    characters = string.ascii_letters + string.digits + string.punctuation
    password = ''.join(random.choice(characters) for _ in range(length))
    print(password)
    ```
    --- end of x.md ---



The syntax is simple, each command is a level 1 header followed by optional documentation in markdown notation, and followed by annotated (which interpreter to use) code block.

One can type `--help` after `x my-command` to print out the help associated with that command.

It is possible to have multiple files with scripts, just put them in the `x` folder with `.md` extension.

Would be very grateful for any suggestions or other feedback.

Thank you.

tonnydourado an hour ago

That's nice, but a tool like this *HAS* to be distributed as a single binary, otherwise it's just too much hassle to bootstrap it, specially on Windows, or stripped out docker containers.

djbusby 16 hours ago

X is kinda overloaded. Maybe "makedown"? Or something?

I just do mine in bash (make.sh) and it runs scripts from make.d/ which are in whatever (python, js bash, PHP)

  • nunobrito 16 hours ago

    Makedown is a good name. +1 vote from me (in case it counts)

    • timz 16 hours ago

      Love the makedown name, renaming.. As for a short name available in terminal, we can add alias m="makedown" as part of zsh completion script. Both: $ makedown deploy-to-production and $ m deploy-to-production --help will work

      Aditionally we can generate html out of the, now `makedown.md`, right in the tool: $ makedown --html makedown.html or $ m --pdf makedown.pdf

      • efilife 12 hours ago

        Remember to change it in the readme as well

divbzero 4 hours ago

This is pretty cool.

For one of my projects, I tried something similar where I had code blocks in README.md like:

  Usage
  -----
  
  `pip install bar` and import `foo`:
  
  ```python
  import foo from bar
  ```
  
  Run `foo.alice` with default arguments:
  
  ```python
  foo.alice()
  ```
  
  Run `foo.bob` while specifying `baz`:
  
  ```python
  foo.bob(baz=0)
  ```
And a Makefile like:

  .PHONY: demo
  demo: venv
      @. .venv/bin/activate; sed -n '/^```python/,/^```/p' < README.md | sed '/^```/d' | python

  .PHONY: venv
  venv: .venv/bin/activate requirements.txt
      @. .venv/bin/activate; pip install -qU pip
      @. .venv/bin/activate; pip install -qUr requirements.txt
  
  .venv/bin/activate:
      @python3 -m venv .venv
So you could run all those README.md code blocks with:

  make demo
timz 4 hours ago

- renamed to `makedown` - rewrote in python, since it is available out of the box on most POSIX and in GitHub actions - Updated to `### [my-command]() Explanation of command` syntax, this way GitHub highlights the commands nicely

Thank you for all the feedback

snake_case 16 hours ago

It’s great to see more tools taking advantage of the markdown syntax.

I’m the creator of Mask[0], a very similar tool built with Rust. I was originally inspired by Maid[1], which is an older take on this idea built with Node and no longer maintained I believe.

I see this is based on Node as well, and I appreciate that it currently has zero dependencies. Nice work!

[0]: https://github.com/jacobdeichert/mask

[1]: https://github.com/egoist/maid

  • ethanwillis 3 hours ago

    Well, which markdown syntax, which specification?

porridgeraisin 3 days ago

It'll be nice if you could make it level 2 headers. Reason: if we want to make it html to display as a webpage, we won't end up with multiple H1s, and we can have a H1 for like the name of the app or something.

  • timz 3 days ago

    Great suggestion. On it

kitd 4 hours ago

Looks nice!

I used XC for a bit, which does a similar thing, but have since reverted to make. The self-documenting nature of these tools can be very useful.

https://xcfile.dev/

rpastuszak 2 hours ago

Aaages ago a I built a little tool to provide a TUI for NPM scripts (https://www.npmjs.com/package/lana-cli)

If you have a README with a list of build tasks, it'll pull its content and give nicer names to whatever is placed in package.json scripts field.

(I'm using comments for that which feels clunky)

I don't update it often, but I still use it almost every day.

fodkodrasz 3 hours ago

Does it support dependency handling between targets, and efficient partial remake of only the changed subtree of the dependency graph? Because what many people miss about make is the support for this, and think it is a way to make "commands" for single level recipies, and auto-complete their names in the shell. A simple shell script would be a trivial solution for that already.

Make does:

- topological sorting based ordering of the dependency tree

- skipping of already up to date targets

- supports parallel execution of independent dependency subtrees

The webpage is totally unclear on this, and to me it looks like it only allows for a named entrypoint to some script snippets.

I'm a literal programming fan though, and this is a nice start, but i recommend clarifying the docs on this.

perpil 7 hours ago

I do something like this with https://speedrun.cc except it runs in the browser on top of your markdown in GitHub. This lets you prompt for inputs and run JavaScript and use a toolbar to context switch. For command lines it copies the command to the clipboard so you can run it.

dsp_person an hour ago

Some ideas:

- can capture output and be updated & displayed in the markdown doc.

- persistent kernels

philsnow 6 hours ago

This reminds me a bit of org-babel’s support for running blocks in any language.

I like the idea and the execution. This bit though:

> makedown.sh

> npm install -g ...

> #!/usr/bin/env python

Gives me a bit of whiplash. I get wanting to use npm to install, since 1) lots of people have it installed and 2) it’s reasonably cross-platform and it seems like makedown is as well.

I don’t see a reason for it to be named makedown.sh instead of just makedown, though. Make itself doesn’t depend on sh to my knowledge, and you could have a makedown file with no shell build rules at all.

  • Izkata 6 hours ago

    > Make itself doesn’t depend on sh to my knowledge

    Recipes are run through sh by default, though it can be overridden to anything using the SHELL variable (including, say, python).

Riverheart 7 hours ago

Really like the simplicity of the project (this is a compliment, the root is not overwhelming with files). Nice that this tool uses only system libraries. Way easier to distribute a single file with leverages already installed languages.

Thanks for sharing!

qazxcvbnm 8 hours ago

For myself, I just make a directory `workflows` and put all my scripts in it, and organise related scripts into subdirectories, so that I can use tree and filesystem tools to check what subcommands are available.

az09mugen 3 days ago

That's an interesting idea you had, it makes me think of a mix between a jupyter notebook and a makefile, sort of, based on md files. I like the concept, but I need to test it to see if it fits my needs. Just a question about python and zsh, do they need to be pre-installed in your OS and accessible from PATH, that's it ?

  • cobalt60 3 days ago

    ansible for markdown?

timz 3 days ago

published 0.3 version pnpm install -g @tzador/x.md

- better --help messages with or without command - ## level 2 headers are used - the temp file is created in current folder, like that importing npm modules from current project works

nunobrito 16 hours ago

Plus points for being a readable format that can be displayed great on HTML or PDF.

At the same time easy to edit and easy to enhance with different build languages as needed.

emareg 12 hours ago

Nice idea! Can I reuse variables that I have defined in e.g. a JS code block in another ZSH code block and vice versa?

cxr 8 hours ago

Just change your README to README.html, and put your build script there.

zahlman 3 days ago

>One can type `--help` after `x my-command` to print out the help associated with that command.

I assume that there is no support for the scripts having their own command-line arguments? Or how do you disambiguate?

Anyway, this seems like an interesting demo, but it's hard to imagine the use case.

  • timz 3 days ago

    When --help is provided, the help text from x.md is printed. Otherwise all the command line parameters are passed to the actual script that implements the command.

donq1xote1 3 hours ago

Hey dude: This is project looks promising. I would like to check out.