Page MenuHomePhabricator

Implement Phurl, a URL shortener/bookmarking application
Open, WishlistPublic

Assigned To
Authored By
Sep 8 2014, 6:06 PM
Referenced Files
"Love" token, awarded by johnny-bit."Piece of Eight" token, awarded by epriestley."Love" token, awarded by 20after4.


Vrana has an old diff for this, in D5147. Rough idea is:

  • Store URLs as objects.
  • They get the Unnn monogram.
  • Global keyboard shortcut to generate a short URL for the current page?
  • Stuff like T5867, T7908 could implement on top of this.

Event Timeline

epriestley raised the priority of this task from to Wishlist.
epriestley updated the task description. (Show Details)
epriestley added a project: Phurl.
epriestley added a subscriber: epriestley.

Walking through some use cases, roughly in increasing order of complexity, and general behaviors -- this is all me just imagining things, not necessarily the best way forward:

General Behaviors

  • /U123 is a standard detail page for a URL, similar to /T123, with things like the transaction record, author, "Edit URL" action, flag, award token, subscribe, etc. It should also have a link like "Visit URL", presumably.
  • Some URL like is the short/redirect URL, which takes you directly to the target/destination. This is shown on the /U123 page, and is what you'd probably paste into an email or chat message if you're purely using Phurl as a URL shortener.

Use Case: Shortener

Alice has a long URL like she wants to pretty up for use in an email or chatroom.

She could use a public URL shortener like or TinyURL to do this, but might prefer not to give this data to an external third party (perhaps the link is an internal link or somewhat sensitive, or she's worried these services could shut down and leave her out in the cold) or might want control or features that Phabricator can provide but a third-party service can't or can't provide as easily (for example, maybe she doesn't want to maintain an external account, but still wants to review links she's saved).

She goes to Phurl and pastes in her huge long URL, and gets a short URL back like This short link is more manageable for use in email, etc. When users visit the short link, they are immediately redirected to the full long URL, just like they would be for a or TinyURL link.

Use Case: Keep Links Up to Date

Bob does support and shortens a link to a common help topic,, to He uses this all over the place to help users turn their stuff off and on again and fix their problems.

After an enterprise upgrade, the link changes. Bob goes to PhurlU2 and ends up at /U2. He clicks "Edit URL" and changes the URL for the link so that it points at the new location. Now all his links still work, even though the resource has moved.

Link Aliases

We can make Phurl URLs a little easier to use by letting users optionally provide a link alias. For example, maybe Bob would prefer to link users to instead of This URL is slightly longer, but a bit easier to remember (and this could make other things easier later on, too). To do this, he could do PhurlU2Edit URL and add an alias, or add an alias when creating the URL in the first place.

The alias would be a unique alphanumeric string like "restart", which could not contain special characters. It also could not be purely numeric (for example, you can't give a link the alias 123, because then U123 and the aliased link would both have the URL /u/123.

If a link has an alias, both /u/2 and /u/restart would still work correctly (adding an alias doesn't break old links). The detail URL is still /U2, and the edit URL is still /phurl/edit/2/ or whatever.


I'd imagine that U2 and {U2} should work like other objects, and embed references to the URLs. When clicked, these references would take you to /U2 (*not* the link destination).

However, it seems useful to also provide a mechanism for directly embedding a Phurl link, maybe with this syntax:


This seems fairly easy to type while remaining unlikely to collide with text in normal use. This would render an alternate form of U2 which took you directly to the link destination when clicked.

For links with aliases, using the alias would also work: above, Bob could type ((restart)).

Possible Use Case: Shorten Current URL

Carly is somewhere in Phabricator with an enormous URL (maybe Diffusion, or future pages in Facts, which are more likely to have a lot of query parameters). She presses a key like "u" and the page pops up a dialog with a short version of the current page URL she can share.

(I'm not sure how useful this really is, but it was one of the original motivating use cases; it is likely to get more useful after Facts is built.)

Possible Use Case: Bookmarks

This is discussed in more detail in T5867.

We could add an option to let users add specific URLs to a global bookmark menu. Something like PhurlU2Add to Bookmarks.

This would cause a new global bookmark menu to appear listing all of the user's bookmarks. They could use these to quickly jump to applications, dashboards, etc., that they commonly reference.

(This feels a bit flimsy to me, but probably isn't too tricky to implement.)

Possible Use Case: Object Aliases

This is roughly discussed in T7908, although that task is pretty meandering.

Instead of aliasing a Phurl to a link, it might be reasonable to alias it to a specific object. Then you could use that alias in other contexts. For example, maybe you create a new Phurl (say, U3) with the "url" of T1049. Phurl recognizes that this is an object, not a real URL, and creates a special object-URL. Other applications can then resolve aliases via Phurl. You add an alias harbormasterv1, then when running arc diff you can type Maniphest Tasks: harbormasterv1 and it figures out that you mean Maniphest Tasks: T1049.

(This feels very flimsy/complicated, and I think aliases on their own solve the original request in T7908.)

Possible Use Case: Tracking

The business value of is in analytics for clicked links (e.g., how many people clicked your link, where did they come from, etc). I don't want to pursue this marketing/tracking angle any time soon, but it's something we could possibly look at eventually.

Possible Use Case: Alternate Short Domain

We could let users configure a short domain which pipes directly into Phurl. For example, an install might be hosted at, but a shorter domain like is configured as the Phurl domain. Phurl then recognizes requests on this domain, and emits URLs using this domain ( The old URLs still work correctly.

With my 'I have a corporate install' hat I think 'Alternate Short Domain' is needed for the 'Shortener' case to work out in practice. is already longer than an entire url. Those two features are probably enough to replace our current internal shortener thingy.

A couple of notes so far, after poking at this:

  • I don't think "Name" should be required. The only thing I should need to plug in is the URL.
  • When written as ((alias)), the link points directly at the target (e.g., linked directly to or whatever). I think it should point at the /u/alias (or /u/id) path instead. This doesn't matter much in practice today, but if we put stat tracking or "You are leaving the site" or a JS-side redirect on it later to strip anchors, it will. This also gets permissions right if you, say, send out a link in an email, but then later restrict visibility on the link.
  • It would be nice to have a global "Can Create URLs" policy for the application. This is particularly useful on open source installs like this one -- without such a policy, some applications get filled up with spammy test nonsense. In the case of Phurl, it's a (very mild) target for "elite hackers" (they can disguise a "dangerous" link as an innocent one). This also generally increases consistency. D14433 is a recent example of how to add such a policy.

Future stuff:

  • It would be nice to put a hovecard on Phurl links with the author/destination, maybe, so you could preview them? This might be silly fluff.

Oh, transaction publishing from Phurl also currently fails in the daemons:

Daemon 106983 STDE [Tue, 10 Nov 2015 22:22:29 +0000] [2015-11-10 22:22:29] EXCEPTION: (PhutilProxyException) Error while executing Task ID 1224759. {>} (Exception) Capability not supported. at [<phabricator>/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php:2479]
Daemon 106983 STDE [Tue, 10 Nov 2015 22:22:29 +0000] arcanist(head=master, ref.master=2db40f995337), phabricator(head=master, ref.master=321c61a853d9), phutil(head=master, ref.master=66bf71f94817)
Daemon 106983 STDE [Tue, 10 Nov 2015 22:22:29 +0000]   #0 <#2> PhabricatorApplicationTransactionEditor::buildReplyHandler(PhabricatorPhurlURL) called at [<phabricator>/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php:2314]
Daemon 106983 STDE [Tue, 10 Nov 2015 22:22:29 +0000]   #1 <#2> PhabricatorApplicationTransactionEditor::buildMail(PhabricatorPhurlURL, array) called at [<phabricator>/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php:1049]
Daemon 106983 STDE [Tue, 10 Nov 2015 22:22:29 +0000]   #2 <#2> PhabricatorApplicationTransactionEditor::publishTransactions(PhabricatorPhurlURL, array) called at [<phabricator>/src/applications/transactions/worker/PhabricatorApplicationTransactionPublishWorker.php:21]
Daemon 106983 STDE [Tue, 10 Nov 2015 22:22:29 +0000]   #3 <#2> PhabricatorApplicationTransactionPublishWorker::doWork() called at [<phabricator>/src/infrastructure/daemon/workers/PhabricatorWorker.php:122]
Daemon 106983 STDE [Tue, 10 Nov 2015 22:22:29 +0000]   #4 <#2> PhabricatorWorker::executeTask() called at [<phabricator>/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php:171]
Daemon 106983 STDE [Tue, 10 Nov 2015 22:22:29 +0000]   #5 <#2> PhabricatorWorkerActiveTask::executeTask() called at [<phabricator>/src/infrastructure/daemon/workers/PhabricatorTaskmasterDaemon.php:22]
Daemon 106983 STDE [Tue, 10 Nov 2015 22:22:29 +0000]   #6 PhabricatorTaskmasterDaemon::run() called at [<phutil>/src/daemon/PhutilDaemon.php:183]
Daemon 106983 STDE [Tue, 10 Nov 2015 22:22:29 +0000]   #7 PhutilDaemon::execute() called at [<phutil>/scripts/daemon/exec/exec_daemon.php:125]

And they don't send mail, as a consequence. D14434 + D14454 are recent examples of implementing this.

Also "Active" in the Object Header should just be the normal color, not green. Our design pattern is "normal" states are plainly colored and exceptional states are actively colored. (red, green, purple).

  • The view page doesn't actually show the short URL anywhere. You can copy it from "View URL", but I think this isn't totally obvious, and we probably have enough room to reasonably add it (e.g., "Short URL: ..." under "Original URL: ...").
  • If a link has an alias, "View URL" still links to the non-alias version (e.g. U6 links to /u/6, but a more-preferred link would be /u/bug).
  • The "Remarkup Reference" document ( should explain how to use ((6)) and ((bug)). It might be worthwhile to hint these on the U6 page itself, e.g. In Remarkup: ((bug)) in the properties? Not sure how useful/cluttered that would look.
  • Maybe show aliases on the list at /phurl/?
  • Maybe let users search for the link with a particular alias? If I know ((bug)), there's no way for me to actually find the URL object right now. Hovercards would be one fix but just going to Phurl and being able to search for "Alias: bug" is probably good too.

If a Phurl doesn't have a name, should we still show the empty name property on the object view?

If a Phurl doesn't have a name, should we still show the empty name property on the object view?

Maybe just show the URL. i.e. have getDisplayName() return the name if it exists, or the URL if it doesn't, and use that?

I've been using the ((alias)) syntax pretty frequently and it's been really helpful -- we have a bunch of documentation we point people at all the time, and before Phurl I'd open a new tab, search for the document, copy-paste the URL, and maybe put some [[ ... | nice title ]] syntax around it. Now I just ((thing)) and it's way easier. The search + copy/paste workflow wasn't hugely time consuming, but it was really annoying.

We're now using Phurl in production for Phacility, too, to render pretty / updatable links in some transactional email.

Out pf curiosity, why not use the @{article:...} syntax instead of copy-pasting the full URL?

Out pf curiosity, why not use the ... syntax instead of copy-pasting the full URL?

Just convenience -- once I'm on the page anyway it's slightly easier for me to copy/paste the URL (since I can do that with keyboard commands: "Command-L, Command-C, Command-W") than the article title.