Bike 1.0 (44) Preview

  • Added AppleScript support
  • Fixed more selection bugs
  • Fixed new documents with “Welcome” text to have unique root ids

The AppleScript dictionary is hopefully pretty standard and understandable. Please let me know where you see problems. There are a few example scripts here to get you started.

Download Bike:


:raised_hands: ‘Home’ button is back! Thanks, @jessegrosjean, loving Bike.


I am quite impressed with your work on the Bike app. It’s lean, nimble and fast. Bike fits into my daily workflow without an ounce of friction. And today’s addition of AppleScript nudges this non-coder into learning a thing or two about how AppleScript works so thank you for those sample scripts that unlocked the simple coding door for me. :grinning:

I don’t need an aircraft carrier. I just need a reliable outliner that doesn’t get in the way of my thinking process. I’m quite happy with Bike.


This osascript library is excellent – particularly for use from AppleScript.

Anyone more accustomed to using osascript -l JavaScript than osascript -l AppleScript may bump into the familiar gap, which Apple never filled, in the implementation of location specifiers for the JS interface.

Where, for example, your very helpful example code at:

AppleScript - Bike


make child row at front

the JS implementation of an osascript interface doesn’t offer us an equivalent of at front, and we can, by default, only insert new objects at the end of collections from JavaScript.

We can get around this, in practice, in various ways, not least by evaluating a tiny AppleScript snippet inline from JS, but I wonder how feasible it might look to implement a pair of osascript methods like:

  • insertBefore
  • insertAfter

(perhaps accepting row id arguments ?) which don’t need osascript location specifiers, and could thus used from JS as well as from AS ?

At the moment, a JS version of your sample:

can be readily written if want to put the new indented rows at the end of a document, but requires some additional thought and gymnastics to insert them at the top of a document using JS :slight_smile:

Far from urgent or essential, but at some point, if it looked feasible, some analogue of the TaskPaper

  • Item.insertChildrenBefore(children, referenceSibling?), or
  • Outline.insertItemsBefore(items, referenceItem)

would simplify placing new rows from JS.

1 Like

Thanks for taking a look! :slight_smile:

See the end of this article where they talk about whose clauses. I think object specifiers might be possible in JavaScript… can those be made to work?

Specialized commands like you suggest are difficult in AppleScript I think. The problem is that the children parameter would need to contain already created items. So to insert a new item at a location that you want you would first need to create item, then move it to location. You couldn’t do in a single “make”.

Generally my feeling is that instead of adding workaround for JavaScript based AppleScript problems (if that makes any sense) I would rather just work on a real JavaScript based scripting layer like what TaskPaper uses, or Omni Automation, etc.

I thought perhaps they might be : -)

a real JavaScript based scripting layer

That would be excellent, and the AppleScript is more than enough to work with at the moment.

JS Object specifiers

We can certainly use .whose / .where clauses etc to specify particular items and subsets of items – the lack of a location specifier implementation in JS just means that we have to do everything in terms of appending to collections – we have no prepend or insert options.

(But everything is ultimately reachable by those methods, and we can also just eval a bit of AppleScript from inside JS)

Ahh, I see, I didn’t realize the difference there.

( No move before or after targets, is another way of summarizing it)

Tho we can write code like this, specifying a row to be moved by its id, and positioning it in relation to the child collection of the document or another row:

Expand disclosure triangle to view JS Source
(() => {
    "use strict";

        idToMove = "lU",
        bike = Application("Bike"),
        doc =,
        row = doc.rows.byId(idToMove);

    return row.exists() ? (
    ) : `Not found: row id ${idToMove}`;