triki is an open source semantic web server. As well as serving out content, triki will also pull in content from other sources of metadata and makes them available from the site. Given this, triki may be better described as a semantic web exchange. triki is targetted at users looking to run their own personal website to share their content. But it can be used to define and serve out any site.

Table of Contents

  1. Background
  2. Installation
  3. Configuration
  4. Content
  5. Metadata
  6. Templates
  7. Presentation
  8. Access Control
  9. Agents
  10. Web Server

1. Background

The full back story is available in series of blogs that I wrote on the subject. They are available here:

Although semantic web technologies are a well developed field it has not been possible to browse a linked data structure easily on the web. Building a linked data structure is the natural way to define our content and how it relates to other content and yet it cannot not be viewed on the web. triki provides a powerful web rendering framework that leverages existing technologies to make a linked data tree browsable.

2. Installation

Build from source

The source for triki is available here It can be built using a Java 1.8 compiler using the following commands:

    git clone
    cd triki
    ./gradlew build

This will create a zip file in build/distributions.

Binary version

Alternatively the latest binary version of triki can be downloaded from bintray at here.


Once unzipped the following directories are available under triki:

To start the example triki site on your own machine do the following sequence of commands:

    cd triki/scripts
    ./ -s

And then browse to http://localhost:8081/resource/home. To stop do:

./ -k

(triki runs on Windows but the start/stop bat files are yet to be written.)

3. Configuration

All configuration is controlled by one .properties file. In the example, this file is called The environment variable TRIKI_PROPERTIES must be set to point to this file location before the start scripts is invoked.

The properties file contains the following settings:

    # Edit as required


    # News properties

    # Groovy extensions dir

    # Need to change importer startup to reference this

4. Content

All content is contained under the top level directory for your site (content_root). Under this directory there is a sub-directory for each file type. Markdown files go in the md directory. CSS files go in the css directory. And so forth, as shown in the example below:

triki directories

Everything is served via triki, even if they are simple static files that could be served directly from an Apache Web Server. The reason for this is that access needs to be controlled by triki, therefore all requests for all content must come through triki.

Static Content

All static file based content is referred to the pattern /content/<filename> e.g. /content/site.css.

Text Documents

By text content, I mean a news story or a blog or a journal or any other content that we want to serve out. A web page basically. The content that backs a web page is written in Markdown and saved as a file under the md directory.

triki uses the pegdown variant for Markdown with the Tables extension enabled.


There are two ways to serve out images. Firstly any image file can just be saved to the /images directory and then referred to as /image/<filename> e.g. /image/directories.png.

The second way is point the importer to a location of photos that you would like to share. The importer will the recursively scan the directory (photos_scanDir) and do the following:

The reason why the images are resized is simply down to to bandwidth. A 20 megapixel camera creates huge files and it is not always practical with self-hosted sites to serve these out. Hence they are auto-resized down to something more reasonable.

Other content

Any other content can also be served out just by creating the appropriate directory name e.g. /pdf/instructions.pdf.

5. Metadata

Metadata is the data about our content. triki stores this information under the ttl directory as a Turtle triples file. There are plenty of the resources available to describe the format, including this primer. The example site shows how an example of the format which hopefully is fairly intuitive and self-explanatory.

For triki, the rules are:

Here is an example of the metadata required to serve out this web page:

    resource:triki a resource:code ;
        dc:creator resource:donaldmcintosh ;
        dc:created "2016-04-13T13:50:00"^^xsd:dateTime ;
        dc:title "triki - A Semantic Web Server" ;
        triki:include ;
        triki:restricted triki:public . triki:restricted triki:public .

The key predicate is triki:include. This is a special predicate the triki uses to "de-reference" (for want of a better term) a reference to a Markdown resource. This is driven by the template however which we will cover next.

6. Templates

triki use StringTemplate to provide templates for every type of web page. StringTemplate templates define templates with holders for data that are substituted at runtime for the actual values. triki uses these templates to blend together data and metadata into an HTML web pages that is ready for viewing. The structure of the site will be 100% controlled by the structure of the backing metadata which is then reflected by the templates.

Templates are saved within the stg directory and are all defined in one file (site_template). The example site contains an extensive stg file which shows the many features of StringTemplate. One of the best features are the closure style via which a sub-template is called, thereby allowing templates to call templates to encourage reuse.

The syntax of StringTemplate is best understood via example. Here is the template drives the Software page on this site:

    software(props) ::= <<

        $props.dc_references :{
                    ref | $reverse(ref.Srdf_type :{
                            code | <div class="blogtitle"><a href='$code.this$'>$code.dc_title$</a></div>


Some things to point out here, as the syntax is fairly terse to say the least:

propsAn object containing metadata for this resource
$header(props)$Call the header() template, passing in props
$$reverse(ref.Srdf_type ...)$Get all subjects that refer to ref via predicate, and reverse the list.
$code.dc_title$Insert the value pointed to by the predicate dc:title
$code.this$Insert the subject resource URL
software(props) ::= << >>Define a template called software
$footer()$Call the footer() template

triki is 100% based on public standards but it does introduce something new here. A way of translating metadata predicates into referenceable predicates had to be defined. The pattern is very simple for standard use case e.g. dc:title becomes dc_title. The : is simply replaced by an underscore. This caters for the standard "forward" case i.e. give me all objects with this predicate for this subject. But semantic web offers another powerful way of exploring our data, which I would call the "backwards" use case.

So as a reminder we triples are declared as shown:

<subject> <predicate> <object>

So the forward use case is where we have the subject and predicate and want to know the objects. The backwards use case is where we have the object and want to know what subjects refer to this predicate. For example:

This backwards reference is made by preceding the predicate with a capital S. This is slightly clunky but it could not be a punctuation character and in translates to "where the Subject is" (rather than Object).

7. Presentation

Final HTML presentation is taken care of with standard CSS style sheets. This will work in any browser on any device and should give a fairly consistent look and feel.

The example site contains an example CSS style sheet.

8. Access Control

All resources served via Triki are controlled by permissions. A resource can be given made public in which case anyone can access it. Alternatively a resource can be associated with a group and users can then be assigned to those groups. If a users is in a group that is permitted to see the resource then it will be available to them.

Here is an example of a group definition with the site triple store:

resource:family foaf:Group "Family" .

FOAF is an ontology called "friend of a friend" and provides predicates for organising groups of people. Then to add people to a group (and others) we do the following:

resource:barbara a foaf:Person ;
    dc:description "Barbara" ;
    triki:login "barbara" ;
    triki:password "password" ;
    foaf:member resource:personal ;
    foaf:member resource:family ;
    foaf:member resource:friends ;

And then to make a resource available to only family and family (say a holiday blog) we would add the following:

resource:corfu-blog triki:restricted resource:family ;
    triki:restricted resource:friends .

For a bigger view on preferred methods of authentication, please read the blog series that introduced triki. This mechanism is very tactical and not something intended for long term usage i.e. the username & password. But the groups and how they are associated with resources is fairly simply and flexible so there is no plan to change this.

One point to note is that if a person is unauthenticated (i.e. a standard anonymous browser session) then they will see secured metadata. The metadata that describes the blog (say) will not be presented to them and, obviously, neither will the blog.

9. Agents

triki uses Agents to go out and pull in interest metadata to your site. This is done asynchronously. By this, we mean that it does not happen when you click the News page, it is being continually updated in the background and when you click the News link you are simply seeing the latest snapshot.

Currently, three types of metadata are supported - RSS, Atom and Twitter. It is possible to define the RSS resources in your triplestore and triki will periodically do an HTTP GET on this resource, parse the results and make them available in your triple store. It is then possible to build up a page that explores this temporary data and returns the latest results.

Here is an example of how an RSS feed is defined:

    resource:guardian a triki:feed;
       dc:created "2016-02-03T16:20:00"^^xsd:dateTime ;
       dc:title "Guardian" ;
       triki:feedurl "" ;
       triki:dateformat "EEE, dd MMM yyyy HH:mm:ss Z" ;
       triki:refresh "live" ;
       triki:feedtype "rss".

Here is an example of how a Twitter search feed can be defined:

    resource:twitter-indieweb a triki:feed;
           dc:created "2016-06-09T20:20:00"^^xsd:dateTime ;
           dc:title "indieweb" ;
           triki:feedurl "" ;
           triki:dateformat "EEE MMM dd HH:mm:ss Z yyyy" ;
           triki:refresh "chatter" ;
           triki:keywords "#indieweb OR ((from:indiewebcamp OR from:kevinmarks OR from:aaronpk OR from:rhiaro) AND -filter:retweets)" ;
           triki:feedtype "twitter".

You can see there are is a refresh of "live" or "chatter" or "feed". These are aliases to configuration that controls how frequently feeds of this type will refresh in the background.

In future it is planned to support SPARQL endpoints.

10. Web Server

At this stage, your site will be availble on your local machine as http://localhost:8081/resource/home. Obviously this needs to be published into the internet. There are many options for self-hosting your site which include:

Any of these options will allow you run your own triki site, addressed by your own personal domain. It will probabaly be necessary to run an Apache Web server in front of triki to take care of translating the publically addressable name back to the local name. To do this use the following configuration:

    <VirtualHost *:80>
        ErrorLog "/root/logs/site-error_log"
        CustomLog "/root/logs/site-access_log" combined

        RewriteEngine    on
        RewriteRule      ^/*$  [R]
        RewriteRule      ^/(.*)$    http://localhost:8081/$1  [P]
        ProxyPassReverse /          http://localhost:8081/